Skip to content

Remove all reserved keywords from schema #9010

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

Closed
AbdelrahmanHafez opened this issue May 16, 2020 · 6 comments
Closed

Remove all reserved keywords from schema #9010

AbdelrahmanHafez opened this issue May 16, 2020 · 6 comments
Assignees
Labels
developer-experience This issue improves error messages, debugging, or reporting
Milestone

Comments

@AbdelrahmanHafez
Copy link
Collaborator

re #8940 (comment) #8940 (comment)

It would be great if we could get rid of entirely of schema reserved keywords.

It's a bit tricky, but I believe it's doable. AFAIK the reason we're having reserved keywords is that we don't want to overwrite document methods.
Even for those, we could allow them and offer alternatives to users, and use that alternative internally. Symbols seem like a good option for internal implementation.

This could be quite useful for people migrating from other types of DBs to MongoDB without having to change their fields' names and don't want their apps to break other apps that depend on their data being the same names.

// user wants to use `validate` as a field name
// it's already present in their SQL DB which they are migrating
const userSchema = new Schema(
  { validate: { type: Boolean } },
  { suppressReservedWarning: true }
);
const User = mongoose.model('User', userSchema);

// if suppressReservedWarning is `false` (the default) compiling this schema
// should log a warning that `validate` field will overwrite a method for documents
// you'll need to use an alternative for those methods
// for more info: https://link.to.docs/alternatives
// this should include a list of alternatives that would still work

const user = new User({ validate: false });


// one alternative would be exporting an immutable object on mongoose
// that has a list of symbols, which we'll use internally
// and let the user use for themselves in this case.

const { validateSymbol } = mongoose.symbols;
await user[validateSymbol]();

// another option, that I don't really like
// is defining methods as statics on model that behave differently
// depending on the arguments.

await User.validate(user);
// at Model.validate, the first line should be
// if (obj instanceof Document) {
//   return obj[validateSymbol]();
// }

Thoughts? @vkarpov15 @lineus

@AbdelrahmanHafez AbdelrahmanHafez added the discussion If you have any thoughts or comments on this issue, please share them! label May 16, 2020
@vkarpov15
Copy link
Collaborator

Good suggestions @AbdelrahmanHafez , I agree with the User.validate() suggestion as well as using symbols for validate().

However, I think we should still expose user.validate() as a method. If the user's schema has a validate property, that property should overwrite the user.validate() method, and if the user tries to use validate() as a method then that's their fault.

The tradeoff is that this will make life more difficult for plugin authors. If you allow validate as a schema path, what happens to plugins that currently rely on calling validate()?

@vkarpov15 vkarpov15 added this to the 6.0 milestone May 23, 2020
@vkarpov15 vkarpov15 added developer-experience This issue improves error messages, debugging, or reporting and removed discussion If you have any thoughts or comments on this issue, please share them! labels May 23, 2020
@AbdelrahmanHafez
Copy link
Collaborator Author

AbdelrahmanHafez commented May 25, 2020

However, I think we should still expose user.validate() as a method.

Yep, that's what I am proposing.

// we should be using that internally
Document.prototype[validateSymbol] = function validate(){};

// exposed to users, if overwritten they should use symbols to access the method
Document.prototype.validate = Document.prototype[validateSymbol];

Users will have access to methods via properties, and if they try to add a path that overwrites the method, we show a warning (that can be suppressed), telling them that if you use that field, you'll overwrite a method, and you'll need to use symbols to access those methods, and refer to a section that explains this further in the docs.

The tradeoff is that this will make life more difficult for plugin authors. If you allow validate as a schema path, what happens to plugins that currently rely on calling validate()?

If users use validate as a path the plugin will break. With that approach, plugin authors should use symbols to access methods to make their plugins usable by all users.

@vkarpov15
Copy link
Collaborator

That's fair. We would have to come up with a list of symbols to export though. Another alternative would be to encourage plugin authors to use Document.prototype.validate.call() to work around the case where the document has a user-defined validate property.

@vkarpov15
Copy link
Collaborator

@AbdelrahmanHafez do you have some time to take a look at this? Would be very helpful.

The only change I'd suggest would be to use Document.prototype.$validate = function validate(){}; rather than Document.prototype[validateSymbol] = function validate(){}; . We've gotten bit before by symbols because many users have multiple versions of Mongoose installed, and symbols are incompatible between multiple installs of Mongoose.

AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 2, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 2, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 9, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 9, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 9, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 9, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 9, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 9, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 9, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 11, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 11, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 27, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 27, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 27, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Jul 27, 2021
@ErnestoBorio
Copy link

I think this is part of the same issue, which has been addressed for other cases such as the option typeKey.
In this case the conflicting attribute name is id but it's part of a sub-document.

import { Schema } from 'mongoose';
const GroupMongoSchema = new Schema(
  {
    slackWorkspace: {
      id: String,
      name: String,
    },
  },
  { id: false, _id: false },
);  

I can workaround this problem by renaming id to something different, but it would break the code style and naming conventions of the project.

I'm getting the Typescript error error TS2589: Type instantiation is excessively deep and possibly infinite. because of this.
Not sure if the id: false option has anything to do with it, but it's not fixing it anyway.

@vkarpov15
Copy link
Collaborator

@ErnestoBorio can you please open a new issue and follow the issue template? Your issue is unrelated.

AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Aug 4, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Aug 4, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Aug 4, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Aug 4, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Aug 4, 2021
AbdelrahmanHafez added a commit to AbdelrahmanHafez/mongoose that referenced this issue Aug 5, 2021
@vkarpov15 vkarpov15 modified the milestones: 6.0.0-rc0, 6.0.0-rc2 Aug 11, 2021
vkarpov15 added a commit that referenced this issue Aug 20, 2021
Allow usage of schema reserved keywords
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
developer-experience This issue improves error messages, debugging, or reporting
Projects
None yet
Development

No branches or pull requests

3 participants