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

Avoid global plugins in model #9780

Closed
chumager opened this issue Jan 7, 2021 · 8 comments
Closed

Avoid global plugins in model #9780

chumager opened this issue Jan 7, 2021 · 8 comments
Labels
new feature This change adds new functionality, like a new method or class
Milestone

Comments

@chumager
Copy link

chumager commented Jan 7, 2021

Do you want to request a feature or report a bug?
Feature
What is the current behavior?
Hi, I've a module who uses mongoose as mutex (with it's own schema and model), to validate the mutex is taken I just insert the document with a unique index, so if I get an E11000 error I know the mutex is taken.

In other hand I've a plugin who checks if a document with unique index can be saved, so instead of throwing a E11000 error it throws a validation error.
My module must be agnostic to the plugins.

Is there a way to tell a schema/model not to apply a global plugin?
If the current behavior is a bug, please provide the steps to reproduce.

"use strict";
const mongoose = require("mongoose");

//comment 2 lines above to make it work
const beautifyUnique = require("mongoose-beautiful-unique-validation");
mongoose.plugin(beautifyUnique);
//a simplified mutex
const mutex = new mongoose.Schema({
  name: {
    type: String,
    unique: true,
    required: true,
  },
});
mutex.static({
  async getMutex(name) {
    try {
      const localMutex = await this.create({name});
      return localMutex;
    } catch (err) {
      if (err.code === 11000) {
        const localError = new Error("mutex can't be acquired");
        localError.name = "mutexError";
        throw localError;
      }
      throw err;
    }
  },
});
mutex.method({
  async release() {
    return await this.remove();
  },
});
const Mutex = mongoose.model("Mutex", mutex);
async function doSomething() {
  try {
    const localMutex = await Mutex.getMutex("test");
    //inner logic...
    //wait for a while
    setTimeout(() => localMutex.release(), 100);
    return true;
  } catch (err) {
    if (err.name === "mutexError") {
      return false;
    }
    //this could be any other logic error
    else throw err;
  }
}
async function main() {
  await mongoose.connect("mongodb://localhost/test", {
    useUnifiedTopology: true,
    useNewUrlParser: true,
    useCreateIndex: true,
  });
  await Mutex.deleteMany(); //just for his test
  //doSomething twice
  for (let i = 0; i < 2; i++) {
    doSomething().then((res) => {
      if (res) console.log(i, "DONE");
      else console.warn(i, "NOT DONE");
    }, console.error);
  }
  await new Promise((res) => setTimeout(res, 200));
  doSomething().then((res) => {
    if (res) console.log("LAST DONE");
    else console.warn("LAST NOT DONE");
  }, console.error);
}
main();

In my code the plugin and the model doesn't know about each other and never will, this is only one example, I've several problems like this.

What is the expected behavior?

That I could use a external module who creates a model and this model don't get global plugins applied.
maybe in the schema options like {plugins: false} or something like that.

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.

mongoose: 5.11.10
mongo: 4.2
node: 14.15.4

@chumager chumager changed the title Avoid plugins in plugin Avoid global plugins in model Jan 7, 2021
@stalniy
Copy link

stalniy commented Jan 8, 2021

Global plugins are not applied after compilation. You may use this to achieve desired behavior

@stalniy
Copy link

stalniy commented Jan 8, 2021

const schema = Schema(...)
const m = mongoose.model(“Mutex”, schema)

mongoose.plugin(...) // this won’t be applied to Mutex

@chumager
Copy link
Author

chumager commented Jan 8, 2021

Thanks @stalniy for the comment, but all related with mongoose it's attached to my fw independently, so as this solutions works it'll implies i'd have to change all my inner logic to load other modules, for example some dev uses my fw and loads the mutex module, it'll be loaded after the fw global plugins.

I think this change could be easy because it's an if before load plugins, maybe the mongoose logic ain't allow it, but if it's easy to develop I think it would be nice.

Regards.

@vkarpov15
Copy link
Collaborator

You can also tell the plugin to explicitly avoid a certain schema:

const plugin = require('myplugin');

mongoose.plugin((schema, options) => {
  if (schema === schemaToExclude) {
    return;
  }
  return plugin(schema, options);
});

@vkarpov15 vkarpov15 added the help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary label Jan 8, 2021
@chumager
Copy link
Author

Yes I know, I can do it, but what about a developer who uses my module?, my issue is to avoid that anyone who uses the module ain't have to acknowledge that he needs to do this, I'm trying to solve a generic problem, if a module must not use any global plugin, is there a way to do it?

Regards.

@vkarpov15 vkarpov15 added new feature This change adds new functionality, like a new method or class and removed help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary labels Jan 13, 2021
@vkarpov15 vkarpov15 added this to the 5.x Unprioritized milestone Jan 13, 2021
@chumager
Copy link
Author

Hi @vkarpov15 how are you?

Any news about this?

I think this could be something like Schema.set("noGlobalPlugin", true)

I'm developing 3 modules, mutex, semaphore and queue, all for multi servers, using mongoose to keep the data structure, this modules uses error control flow, so any mongoose plugin that will change errors will make those modules to fail.

Regards.

@vkarpov15 vkarpov15 modified the milestones: 6.x Unprioritized, 6.1.0 Nov 29, 2021
@vkarpov15
Copy link
Collaborator

@chumager no progress yet, but we can add a tags system for v6.1.0. Something like:

Schema.set('tags', ['mutex']);

And

mongoose.plugin(mutexPlugin, { tags: 'mutex' }); // Only apply plugin to schemas with 'mutex' tag

Would that help?

@chumager
Copy link
Author

chumager commented Dec 2, 2021

Hi @vkarpov15, I already solved for mi FW, my problem is if someone uses my modules, I added caveats in the readme.

instead of mongoose.plugin(plugin, options) I added a wrapper.

//for each global plugin
mongoose.plugin((schema, options)=>{
  if (!schema.get("noGlobalPlugin")) schema.plugin(plugin, options);
}, options);

@vkarpov15 vkarpov15 modified the milestones: 6.1.0, 6.2.0 Dec 2, 2021
vkarpov15 added a commit that referenced this issue Jan 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature This change adds new functionality, like a new method or class
Projects
None yet
Development

No branches or pull requests

3 participants