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

[interop] Array default with transfrom #8012

Closed
hasezoey opened this issue Jul 24, 2019 · 17 comments
Closed

[interop] Array default with transfrom #8012

hasezoey opened this issue Jul 24, 2019 · 17 comments
Labels
docs This issue is due to a mistake or omission in the mongoosejs.com documentation
Milestone

Comments

@hasezoey
Copy link
Collaborator

mongoose version: 5.6.6(NPM)
nodejs: 12.7.0

reproduce script:

import * as mongoose from "mongoose";

const testSchema = new mongoose.Schema({
    testArray: [{ default: ["testDefault"], type: String, lowercase: true }]
});

const testModel = mongoose.model("test", testSchema);

(async () => {
    mongoose.set("debug", true);
    await mongoose.connect(`mongodb://mongodb:27017/`, {
        useNewUrlParser: true,
        useFindAndModify: true,
        useCreateIndex: true,
        dbName: "verify",
        user: "user",
        pass: "passwd",
        authSource: "admin",
        autoIndex: true
    });

    const doc = new testModel({});
    await doc.save();
    console.log(doc.toObject());

    await mongoose.disconnect();
})();

log

Mongoose: tests.insertOne({ testArray: [], _id: ObjectId("5d38883c65478f080346dfad"), __v: 0 }, { session: null })
{ testArray: [], _id: 5d38883c65478f080346dfad, __v: 0 }

current behavior: dosnt apply the default value when formatted so / has a "string" transform
wanted behavior: applys default value when formatted so

PS: i make this a question, because i dont know if this is an actual bug
and if there is actually an other issue having this problem, i didnt find it...

@vkarpov15 vkarpov15 added this to the 5.6.8 milestone Jul 29, 2019
@vkarpov15 vkarpov15 added the has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue label Jul 29, 2019
@hasezoey hasezoey changed the title [Question] Array default with transfrom [Bug] Array default with transfrom Jul 30, 2019
vkarpov15 added a commit that referenced this issue Jul 30, 2019
@vkarpov15 vkarpov15 modified the milestones: 5.6.8, 5.7 Jul 30, 2019
@vkarpov15 vkarpov15 added enhancement This issue is a user-facing general improvement that doesn't fix a bug or add a new feature and removed has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels Jul 30, 2019
@vkarpov15
Copy link
Collaborator

Going to postpone this until 5.7.0 because I think this is a bit too risky for a patch release.

@hasezoey
Copy link
Collaborator Author

hasezoey commented Sep 10, 2019

@vkarpov15 after testing it in mongoose@5.7.0 the initial example i gave, dosnt work, but others do

works:

import * as mongoose from "mongoose";

const testSchema = new mongoose.Schema({
  testArray: [{ type: String, lowercase: true }]
});

const testModel = mongoose.model("test", testSchema);

(async () => {
  mongoose.set("debug", true);
  await mongoose.connect(`mongodb://localhost:27017/verify`, {
    useNewUrlParser: true,
    useFindAndModify: true,
    useCreateIndex: true,
    autoIndex: true
  });

  const doc = await testModel.create({ testArray: ["MAKE ME LOWERCASE"] });
  console.log(doc.toObject());

  await mongoose.disconnect();
})();

// result:
// {"testArray":["make me lowercase"],"_id":"5d772503932ef4351940bff4","__v":0}

dosnt work:

import * as mongoose from "mongoose";

const testSchema = new mongoose.Schema({
  testArray: [{ default: ["testDefault"], type: String, lowercase: true }]
});

const testModel = mongoose.model("test", testSchema);

(async () => {
  mongoose.set("debug", true);
  await mongoose.connect(`mongodb://localhost:27017/verify`, {
    useNewUrlParser: true,
    useFindAndModify: true,
    useCreateIndex: true,
    autoIndex: true
  });

  const doc = await testModel.create({});
  console.log(doc.toObject());

  await mongoose.disconnect();
})();
// result:
// { testArray: [], _id: 5d77249e9341eb34490df597, __v: 0 }

so my assumption is that default dosnt get applied to arrays when defined so

PS: sorry for not testing it earlier

@vkarpov15 vkarpov15 reopened this Sep 10, 2019
@vkarpov15 vkarpov15 modified the milestones: 5.7, 5.7.1 Sep 10, 2019
@vkarpov15 vkarpov15 added has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue and removed enhancement This issue is a user-facing general improvement that doesn't fix a bug or add a new feature fixed? labels Sep 10, 2019
@vkarpov15
Copy link
Collaborator

@hasezoey that's because you're defining the default on the individual array values, not on the array as a whole. If you define your schema as shown below, it works fine.

const testSchema = new mongoose.Schema({
  testArray: {
    type: [{ type: String, lowercase: true }],
    default: ["testDefault"]
  }
});

@vkarpov15 vkarpov15 modified the milestones: 5.7.1, 5.7 Sep 12, 2019
@vkarpov15 vkarpov15 added fixed? and removed has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels Sep 12, 2019
@hasezoey
Copy link
Collaborator Author

hasezoey commented Oct 14, 2019

Thanks for implementing it and for the documentation, but now where i try to implement it, i got some question on how to use it, because:

  • mongoose.Schema.Types.String.prototype.OptionsConstructor instanceof mongoose.SchemaTypeOptions returns false
  • and (example) trim dosnt exists on mongoose.Schema.Types.String.prototype.OptionsConstructor

what i more fully mean:

// "Type" can be something like "mongoose.Types.String"
// logger is npm package "log-level"
const returnObject = {
  type: [{
    type: Type
  }]
};

// @ts-ignore
if (Type.prototype.OptionsConstructor instanceof mongoose.SchemaTypeOptions) { // returns false
  for (const [key, value] of Object.entries(options)) {
    if (key in Type.prototype.OptionsConstructor) { // when disabling the "returns false" check above, this always takes the else route
      logger.debug('Value is in OC:', key);
      returnObject.type[0][key] = value;
    } else {
      logger.debug('Value is not in OC:', key);
      returnObject[key] = value;
    }
  }

  logger.debug('final obj', returnObject);
}

am i just using it wrong? @vkarpov15


and from the documentation schema.path('name').options instanceof mongoose.SchemaTypeOptions; // true i cant use, because this is needed before a schema creation


update:
is mongoose.Schema.Types.String.prototype.OptionsConstructor.prototype the only option to get the settings? because this way, it only includes the options of "String" and not the ones from "SchemaTypeOptions" (like required is not present)


node: 12.11.1
mongoose: 5.7.5
typescript: 3.6.3

@hasezoey hasezoey changed the title [Bug] Array default with transfrom [interop] Array default with transfrom Oct 14, 2019
@vkarpov15
Copy link
Collaborator

mongoose.Schema.Types.String.prototype.OptionsConstructor is the constructor used to instantiate options, not an instance of options. For example, you'll see mongoose.Schema.Types.Boolean.prototype.OptionsConstructor === mongoose.SchemaTypeOptions. And, similarly:

> Object.getOwnPropertyDescriptor(mongoose.Schema.Types.String.prototype.OptionsConstructor.prototype, 'trim')
{ value: null,
  writable: true,
  enumerable: true,
  configurable: true }
> 
> Object.getOwnPropertyNames(mongoose.Schema.Types.String.prototype.OptionsConstructor.prototype)
[ 'constructor', 'enum', 'match', 'lowercase', 'trim', 'uppercase' ]
> 

Sorry for the long stream of dots and prototypes. Might be easier to just export mongoose.SchemaStringOptions so you can do Object.getOwnPropertyNames(mongoose.SchemaStringOptions.prototype)

@hasezoey
Copy link
Collaborator Author

hasezoey commented Oct 17, 2019

Sorry for the long stream of dots and prototypes. Might be easier to just export

im fine with it, as long as it is consistent


For example, you'll see mongoose.Schema.Types.Boolean.prototype.OptionsConstructor === mongoose.SchemaTypeOptions = true

but mongoose.Schema.Types.String.prototype.OptionsConstructor === mongoose.SchemaTypeOptions = false

-> it seems like Schema.Types.Boolean does not have an entry in lib/options, just wanted to share that, might be right so or forgotten, i dont know


it seems the type Schema.Types.String is missing some options, like maxlength, minlength @vkarpov15

Update: i made an new issue for this


Thanks for this, it made the typegoose code more understandable & maintainable instead of having to redefine the options when mongoose updates :)

@vkarpov15
Copy link
Collaborator

No but mongoose.Schema.Types.String.prototype.OptionsConstructor is a class that inherits from mongoose.SchemaTypeOption.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This issue is due to a mistake or omission in the mongoosejs.com documentation
Projects
None yet
Development

No branches or pull requests

2 participants