Return a value from inside a Fiber

149 views Asked by At

I'm trying to provide a collection having its methods wrapped in fibers for synchronous looking calls.

const Fiber = require('fibers');
const wrapInFiber = require('./wrapInFiber');

let db;
Fiber(function () {
  db = wrapInFiber({
    url: global.__MONGO_URI__,
    config: { useNewUrlParser: true, useUnifiedTopology: true },
    databaseName: global.__MONGO_DB_NAME__,
    collections: ['users'],
  });
  console.log('DB', db.users);
}).run();

module.exports.Users = db.users; <-- undefined

Console log outputs the value but db.users passed to the module.exports is undefined because either it runs before the fiber is done or rather outside the fiber, I presume? So, how can I pass the value to the module.exports correctly?

The only remotely close answer is this one which I tried to mimic but failed, maybe because his wrapped function involved no fibers related code unlike mine.

WrapInFiber just in case. It's adapted from this library.


const Fiber = require('fibers');
const { MongoClient } = require('mongodb');

module.exports = function ({ url, config, databaseName, collections }) {
  const Collection = function (db, name) {
    this.collection = db.collection(name);
  };

  Collection.prototype.count = function (query, options) {
    query = query || {};
    options = options || {};
    const fiber = Fiber.current;
    this.collection.count(query, options, function (err, records) {
      fiber.run(records);
    });
    return Fiber.yield();
  };

  Collection.prototype.find = function (query, options) {
    query = query || {};
    options = options || {};
    const fiber = Fiber.current;
    this.collection.find(query, options).toArray(function (err, records) {
      fiber.run(records);
    });
    return Fiber.yield();
  };

  Collection.prototype.findOne = function (query, options) {
    return this.find(query, options)[0];
  };

  Collection.prototype.update = function (query, options) {
    const fiber = Fiber.current;
    this.collection.update(query, options, function (err, records) {
      fiber.run(records);
    });
    return Fiber.yield();
  };

  Collection.prototype.insert = function (document) {
    const fiber = Fiber.current;
    this.collection.insert(document, function (err, records) {
      fiber.run(records);
    });
    return Fiber.yield();
  };

  Collection.prototype.remove = function (document) {
    const fiber = Fiber.current;
    this.collection.remove(document, function (err, records) {
      fiber.run(records);
    });
    return Fiber.yield();
  };

  const fiber = Fiber.current;

  MongoClient.connect(url, config, function (err, connection) {
    const obj = {
      close() {
        connection.close();
      },
    };
    const db = connection.db(databaseName);
    collections.forEach(function (collectionName) {
      obj[collectionName] = new Collection(db, collectionName);
    });
    fiber.run(obj);
  });

  return Fiber.yield();
};

1

There are 1 answers

0
Harry Adel On

While I didn't solve the issues of fibers I managed to solve the initial problem which led to this path of stubbing Meteor collections. All it took was a simple Sinon stub.

const sinon = require('sinon');
require('sinon-mongo');

const Users = sinon.mongo.collection({
  findOne: sinon
    .stub()
    .withArgs({ _id: 'user' }, { fields: { roles: 1 } })
    .returns({ _id: 'user', roles: [] }),
});

module.exports.Users = Users;