Uploaded image for project: 'MongoDB Shell'
  1. MongoDB Shell
  2. MONGOSH-651

Productize new async rewriter

    XMLWordPrintable

Details

    • Task
    • Status: Closed
    • Major - P3
    • Resolution: Fixed
    • None
    • 0.12.0
    • AsyncWriter
    • None
    • Needed
    • Hide
      We have made some internal changes to how mongosh processes the JavaScript code that it receives as input. (This affects the built-in shell in Compass and VSCode playground as well, if it matters).

      I don’t think we have previously documented the limitations that we were imposing on users. Luckily, there’s only few left, and it’s not going to be a common occurrence for people to encounter them, but we should document them:

      The results of database calls, directly or indirectly through other functions, cannot be used in three contexts, namely, inside class constructor functions, inside non-async generator functions, and inside callbacks to {{array.sort()}}. As a workaround, wrapping the access to db results in async functions or using async generator functions works, respectively.

      Concretely, this means:

      {code}
      // For constructors:
      // ------------------------
      // This will not work
      class SomeClass {
        constructor() {
          this.value = db.coll.find();
        }
      }

      // Neither will this
      function listEntries() { return db.coll.find(); }
      class SomeClass {
        constructor() {
          this.value = listEntries();
        }
      }

      // But this can be used instead, if it also fits the purpose here:
      class SomeClass {
        constructor() {
          this.value = (async() => {
            return db.coll.find();
          })();
        }
      }

      // For generator functions:
      // ------------------------
      // This will not work
      function* someGenerator() {
        yield db.coll.find();
      }

      // Neither will this
      function listEntries() { return db.coll.find(); }
      function* someGenerator() {
        yield listEntries();
      }

      // But this can be used instead, if it also fits the purpose here:
      function listEntries() { return db.coll.find(); }
      async function* someGenerator() {
        yield listEntries();
      }

      // For array.sort:
      // ------------------------
      // This will not work
      db.getCollectionNames().sort((coll1, coll2) => {
        return db[coll1].estimatedDocumentCount() - db[coll2].estimatedDocumentCount())
      });

      // But this approach can be used instead (and is often more performant):
      db.getCollectionNames().map(collName => {
        return { collName, size: db[collName].estimatedDocumentCount() };
      }).sort((coll1, coll2) => {
        return coll1.size - coll2.size;
      }).map(coll => coll.collName);
      {code}

      Show
      We have made some internal changes to how mongosh processes the JavaScript code that it receives as input. (This affects the built-in shell in Compass and VSCode playground as well, if it matters). I don’t think we have previously documented the limitations that we were imposing on users. Luckily, there’s only few left, and it’s not going to be a common occurrence for people to encounter them, but we should document them: The results of database calls, directly or indirectly through other functions, cannot be used in three contexts, namely, inside class constructor functions, inside non-async generator functions, and inside callbacks to {{array.sort()}}. As a workaround, wrapping the access to db results in async functions or using async generator functions works, respectively. Concretely, this means: {code} // For constructors: // ------------------------ // This will not work class SomeClass {   constructor() {     this.value = db.coll.find();   } } // Neither will this function listEntries() { return db.coll.find(); } class SomeClass {   constructor() {     this.value = listEntries();   } } // But this can be used instead, if it also fits the purpose here: class SomeClass {   constructor() {     this.value = (async() => {       return db.coll.find();     })();   } } // For generator functions: // ------------------------ // This will not work function* someGenerator() {   yield db.coll.find(); } // Neither will this function listEntries() { return db.coll.find(); } function* someGenerator() {   yield listEntries(); } // But this can be used instead, if it also fits the purpose here: function listEntries() { return db.coll.find(); } async function* someGenerator() {   yield listEntries(); } // For array.sort: // ------------------------ // This will not work db.getCollectionNames().sort((coll1, coll2) => {   return db[coll1].estimatedDocumentCount() - db[coll2].estimatedDocumentCount()) }); // But this approach can be used instead (and is often more performant): db.getCollectionNames().map(collName => {   return { collName, size: db[collName].estimatedDocumentCount() }; }).sort((coll1, coll2) => {   return coll1.size - coll2.size; }).map(coll => coll.collName); {code}
    • Iteration Z

    Description

      A few things that we should improve:

      • Readable/useful error messages
      • Documentation of what is not supported (and workarounds if they exist)
      • Testing

      Once we feel confident that the new rewriter is ready, we can switch to that by default. Let's evaluate whether we want to keep the other one around for a bit just in case or if we want to get rid of it.

      Attachments

        Issue Links

          Activity

            People

              anna.henningsen@mongodb.com Anna Henningsen
              massimiliano.marcon@mongodb.com Massimiliano Marcon
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: