francescov1 / mongoose-tsgen

A plug-n-play Typescript generator for Mongoose.
102 stars 24 forks source link

mongoose.Document<never> #151

Closed adrianwiechec-at-optilyz closed 2 months ago

adrianwiechec-at-optilyz commented 3 months ago

I got this weird situation where

import { Schema, model } from "mongoose";

const UserSchema = new Schema({
  arrayField: [
    {
      _id: false,
      objectField: { type: { stringField: String } },
    },
  ],
});

export const User = model("User", UserSchema);

produces:

export type UserArrayFieldObjectFieldDocument = mongoose.Document<never> & { // "never" ?!!!!!!!!!!!
  stringField?: string;
  _id: mongoose.Types.ObjectId;
};

export type UserArrayFieldDocument = mongoose.Types.Subdocument & {
  objectField?: UserArrayFieldObjectFieldDocument;
};

which results in objectField?: undefined :(

Sorry for the schema being a bit convoluted, that's the smallest combination I was able to reproduce with. In particular, both _id: false and type: are necessary.

francescov1 commented 2 months ago

Hey @adrianwiechec-at-optilyz, sorry to hear, could you clarify what the actual mongodb shape of objectField: { type: { stringField: String } } is supposed to look like? The conflict is arising because the type keyword has a special meaning in Mongoose, so Im wondering if you're trying to define a field called type or if you are specifying the actual type of the objectField field

adrianwiechec-at-optilyz commented 2 months ago

The latter, I'm specifiying the actual type of the objectField field. Obviously in production there's some more fields in there (plus a required or default clause), this is just a simplified reproduction case.

francescov1 commented 2 months ago

Ah got it, I believe your schema may be incorrect then (or maybe its just a niche edge case format that mongoose-tsgen isnt handling). The more common approach would be to define the schema like this:

import { Schema, model } from "mongoose";

const UserSchema = new Schema({
  arrayField: [
    {
      _id: false,
      objectField: { stringField: String },
    },
  ],
});

export const User = model("User", UserSchema);

Does that accomplish the same goal for you? If not I can add support for your syntax, but It's the first time I've seen it so want to ensure its valid Mongoose syntax

adrianwiechec-at-optilyz commented 2 months ago

What we actually have in the codebase is more akin to:

  const schema = {
    arrayOfMappings: [
      {
        _id: false,
        fieldName: String,
        extension: {
          type: {
            customer: String,
            path: [String],
          },
          default: null,
        },
      },
    ],
  };

  const UserSchema = new Schema(schema);

but AFAIK it doesn't matter that much. Isn't: field: String just a shortcut notation for: field: {type: String} ?

francescov1 commented 2 months ago

ah okay i see the use case now. Yes youre right that its just a shortcut; it just results in complicated logic to determine when something is a "type" vs when the user wants to define a field called "type". And gets more hairy when there's a complex data structure under the type field

Ill take a look and see if there's an easy fix for this. But Im currently in the middle of a big refactor that will make resolving this a lot easier, so if there isnt anything apparent then Ill finish that up first then come back to this. Will keep you updated

francescov1 commented 2 months ago

Okay turns out that the issue has nothing to do with the type field, its actually only the _id: false causing issues.

Mongoose Document type accepts a generic argument to type the _id field. So Document<string> would result in a Document with _id: string. So in the case where the user sets _id: false, mongoose-tsgen was passing never as the _id type, Document<never>. For some reason, doing this turns the entire document into a "never"...

So easy fix, Im going to change the never to an any. From looking at the mongoose types, there isnt an easy way to remove the _id field completely from the TS definition. In the future ill explore if its possible but this should resolve your issue for now.

francescov1 commented 2 months ago

Fix is live in v9.3.5 🚀

adrianwiechec-at-optilyz commented 2 months ago

Once again, thanks for your help! :bow: