sourced-repo-mongo icon indicating copy to clipboard operation
sourced-repo-mongo copied to clipboard

Repository.getAll() fails with async/await / util.promisify

Open AlexZeitler opened this issue 8 years ago • 8 comments
trafficstars

I tried using source-repo-mongo with Node 8 and async / await + util.promisify from Node 8.

This is my code:

"use strict";

const Entity = require("sourced").Entity;
const util = require("util");
const promisify = util.promisify;
const Repository = require("sourced-repo-mongo").Repository;
const mongo = require("sourced-repo-mongo/mongo");

function Customer() {
  this.id = null;
  this.name = null;
  Entity.apply(this, arguments);
}

util.inherits(Customer, Entity);

const start = async function() {
  return new Promise(async (resolve, reject) => {
    const uri = "mongodb://localhost:27017/";
    console.log("connecting");

    mongo.once("connected", async () => {
      console.log(`connected`);
      const repo = new Repository(Customer);
      const getAll = promisify(repo.getAll);

      try {
        console.log(`getting customers`);
        const customers = await getAll();
        console.log("customers", customers);
        return resolve();
      } catch (err) {
        return reject(err);
      }
    });

    mongo.connect(uri);
  });
};

start();

Running this code results in TypeError: Cannot read property 'distinct' of undefined after the await getAll() call.

AlexZeitler avatar Jun 17 '17 19:06 AlexZeitler

The same happens when using bluebirds promisify function as suggested in https://github.com/mateodelnorte/sourced-repo-mongo/issues/13#issuecomment-239321801

AlexZeitler avatar Jun 17 '17 19:06 AlexZeitler

I think it's a timing issue, regarding the repo's ready event. I don't see anything that should be async, between the new call and it's usage, but you're likely getting an error on this line and self.events.distinct property.

self.events is set here. Again, it's a little funny, as I don't see any async ops going on between that property being set and the usage.

Does changing your usage to something like the following help?

    mongo.once("connected", async () => {
      console.log(`connected`);
      const repo = new Repository(Customer);
      repo.on('ready', () => {
        const getAll = promisify(repo.getAll);

        try {
          console.log(`getting customers`);
          const customers = await getAll();
          console.log("customers", customers);
          return resolve();
        } catch (err) {
          return reject(err);
        }
      });
    });  

mateodelnorte avatar Jun 21 '17 17:06 mateodelnorte

Dunno if it's somehow manifesting itself with the usage, but I usually just put my repo definitions in their own file.

const Trader = require('./models/trader');
const Repo = require('sourced-repo-mongo').Repository;
const util = require('util');

function TraderRepository () {
  Repo.call(this, Trader);
}

util.inherits(TraderRepository, Repo);

module.exports = new TraderRepository();

This ends up being helpful if I start using the decorator pattern to add over overlay behavior on the new repo type:

const Trader = require('./models/trader');
const Repo = require('sourced-repo-mongo').Repository;
const Queued = require('sourced-queued-repo');
const util = require('util');

function TraderRepository () {
  Repo.call(this, Trader);
}

util.inherits(TraderRepository, Repo);

module.exports = Queued(new TraderRepository());

mateodelnorte avatar Jun 21 '17 17:06 mateodelnorte

@mateodelnorte Thanks for your reply. In fact, my initial code looked quite similar to your second suggestion. My sample above was just simplified for repro.

AlexZeitler avatar Jun 21 '17 19:06 AlexZeitler

Are you still having the issue? Otherwise, did you try the suggestion here.

mateodelnorte avatar Jun 21 '17 20:06 mateodelnorte

Yes, I'm still having the issue (if I'm not using a workaround wrapping the sourced-repo-mongo calls in Promises which are called using async/await then).

If I'm using your code as suggested:

mongo.once("connected", async () => {
      console.log(`connected`);
      const repo = new Repository(Customer);
      repo.on('ready', () => {
        console.log('ready')
        const getAll = promisify(repo.getAll);

        try {
          console.log(`getting customers`);
          const customers = await getAll();
          console.log("customers", customers);
          return resolve();
        } catch (err) {
          return reject(err);
        }
      });
    });  

I'm getting this error:

const customers = await getAll();
                        ^^^^^^

SyntaxError: Unexpected identifier
    at createScript (vm.js:74:10)
    at Object.runInThisContext (vm.js:116:10)
    at Module._compile (module.js:533:28)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)
    at Function.Module.runMain (module.js:605:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3

If I add the async keyword like shown here:

mongo.once("connected", async () => {
      console.log(`connected`);
      const repo = new Repository(Customer);
      repo.on('ready', async () => { // async added here
        console.log('ready')
        const getAll = promisify(repo.getAll);

        try {
          console.log(`getting customers`);
          const customers = await getAll();
          console.log("customers", customers);
          return resolve();
        } catch (err) {
          return reject(err);
        }
      });
    });  

I don't get any errors, but it looks like the ready event of repo is never executed:

⋙  node index.js
connecting
connected

AlexZeitler avatar Jun 21 '17 20:06 AlexZeitler

@AlexZeitler Did you ever find a workaround for this?

I too have not been able to connect to the ready event of any Repository instance.

pcopley avatar Jun 03 '21 18:06 pcopley

@pcopley No, didn't solve it.

AlexZeitler avatar Jun 06 '21 21:06 AlexZeitler