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

Empty object type #883

Closed
wasya243 opened this issue Sep 26, 2023 · 7 comments
Closed

Empty object type #883

wasya243 opened this issue Sep 26, 2023 · 7 comments
Labels
question Qustions about how to use stuff

Comments

@wasya243
Copy link

wasya243 commented Sep 26, 2023

Hello, it's related to #882. I probably need your help.

const options = { _id: false };
const objSchema = new mongoose.Schema({}, options);

const usersPermissions = {
  superAdmin: objSchema,
  settings: objSchema,
  user_management: new mongoose.Schema({
    permissions_management: objSchema,
    acc_permission: objSchema
    qaa_permission: objSchema
  }, options),
};

export default  usersPermissions;

Basically it means this structure will only hold empty objects and nothing else (even If I pass not empty objects on write -> it will ignore the data and will write {}). For example ->

{
  superAdmin: {},
  settings: {}
}

or

{
  superAdmin: {},
  settings: {},
  user_management: {
    acc_permission: {}
  }
}

I can only achieve it with setter -> set: () => { return {{}}. Maybe there is other way?

@wasya243 wasya243 added the question Qustions about how to use stuff label Sep 26, 2023
@hasezoey
Copy link
Member

i dont understand your question, what are you trying to achieve and how is it currently working?

also for questions, consider using github discussions next time

@wasya243
Copy link
Author

wasya243 commented Sep 26, 2023

There is a legacy thing. I don't know why, but it stores the following data structure ->

{
    "superAdmin" : {},
    "settings" : {},
    "user_management" : {
    	"permissions_management": {},
    	"acc_permission": {}
    	"qaa_permission": {}
    },
}

So basically if "settings" or "qaa_permission" is present (and equal to {}) -> it means feature is enabled. So, I know it's bullshit and it should have been bool, but it's what it is... So, I'm trying to describe the following schema in typegoose.

const options = { _id: false };
const objSchema = new mongoose.Schema({}, options);

const usersPermissions = new mongoose.Schema{
  superAdmin: objSchema,
  settings: objSchema,
  user_management: new mongoose.Schema({
    permissions_management: objSchema,
    acc_permission: objSchema
    qaa_permission: objSchema
  }, {...options, minimize: true}),
};

export default  usersPermissions;

Unfortunately Recod<string, unknown> does not fit here -> it allows anything to be written to "superAdmin" property or "settings", but I only need empty object and nothing else.

@hasezoey
Copy link
Member

hasezoey commented Sep 26, 2023

i think you just ran into what i had updated my message (#882 (comment)) right after the issue was closed, just stating it here again:

*: this is not actually a 1:1, the 1:1 would be a empty class, but empty classes dont work very well (they are seemingly not unique), so for this use case the translation above is what you would want

the Record<string, any> was the approach i recommend, at least with what was available at the time

with the information available now, i would recommend:

  • stay with Record<string, any> and use a setter of {}
  • use a dummy class *1
  • use type: new mongoose.Schema({}, { _id: false }) (should work, though i have not actually tested it)

*1 previously there were some issues with plain empty classes and typegoose, but i dont fully recall what those issues were exactly (from what i do recall it had something todo with types being unknown and maybe something in the old cache not working)

the most typegoose solution:

@modelOptions({ schemaOptions: { _id: false } })
class Empty {}

class Test {
  @prop()
  public b?: Empty;
}

(this only works if strict option is enabled globally / for the schema, which it is by default)


Edit:

a true 1:1 translation of the code provided in #883 (comment), is:

@modelOptions({ schemaOptions: { _id: false } })
class ObjSchema {}

@modelOptions({ schemaOptions: { _id: false, minimize: true } })
class UserManagement {
  @prop()
  public permissions_management?: ObjSchema;

  @prop()
  public acc_permissions?: ObjSchema;

  @prop()
  public qaa_permissions?: ObjSchema;
}

class UserPermissions {
  @prop()
  public superAdmin?: ObjSchema;

  @prop()
  public settings?: ObjSchema;

  @prop()
  public user_management?: UserManagement;
}

though now looking at the schema options again, you are using minimize, does this not defeat the purpose? because to my knowledge it removes properties which are empty like t: {} or t: [] would be removed and not saved?

@wasya243
Copy link
Author

wasya243 commented Sep 27, 2023

@hasezoey hello, I use minimize: false, so that mongoose does not remove empty object. Regarding everything discussed above -> it does not work(( I mean empty object schema or setter for empty object. To be precise user_management. It's always saved as an empty object (even if I pass acc_permissions or other props). Seems to be minimize: false is not propagated to nested object (user_managemen) on user permissions. FYI I tried adding this option to UserManagement and it did not work as well.

@hasezoey
Copy link
Member

@hasezoey hello, I use minimize: false, so that mongoose does not remove empty object. Regarding everything discussed above -> it does not work(( I mean empty object schema or setter for empty object. To be precise user_management. It's always saved as an empty object (even if I pass acc_permissions or other props). Seems to be minimize: false is not propagated to nested object (user_managemen) on user permissions. FYI I tried adding this option to UserManagement and it did not work as well.

i dont know what you tried, but the following code:

// NodeJS: 20.5.1
// MongoDB: 5.0 (Docker)
// Typescript 4.9.5
import { getModelForClass, modelOptions, prop } from '@typegoose/typegoose'; // @typegoose/typegoose@11.4.0
import * as mongoose from 'mongoose'; // mongoose@7.4.0

@modelOptions({ schemaOptions: { _id: false } })
class ObjSchema {}

@modelOptions({ schemaOptions: { _id: false, minimize: false } })
class UserManagement {
  @prop()
  public permissions_management?: ObjSchema;

  @prop()
  public acc_permissions?: ObjSchema;

  @prop()
  public qaa_permissions?: ObjSchema;
}

@modelOptions({ schemaOptions: { minimize: false } })
class UserPermissions {
  @prop()
  public superAdmin?: ObjSchema;

  @prop()
  public settings?: ObjSchema;

  @prop()
  public user_management?: UserManagement;
}

const UserPermissionsModel = getModelForClass(UserPermissions);

async function main() {
  await mongoose.connect(`mongodb://localhost:27017/`, {
    dbName: 'verifyMASTER',
  });

  const doc = await UserPermissionsModel.create({ superAdmin: { a: 'hello' }, user_management: { acc_permissions: { b: 'hello' } } });

  console.log('doc', doc);

  const found = await UserPermissionsModel.findById(doc).orFail();

  console.log('found', found);

  found.settings = { c: 'hello' };

  await found.save();

  console.log('found save', found);

  await mongoose.disconnect();
}

main();

gives output:

doc {
  superAdmin: {},
  user_management: { acc_permissions: {} },
  _id: new ObjectId("65140fdd48d3d0b650b16df1"),
  __v: 0
}
found {
  _id: new ObjectId("65140fdd48d3d0b650b16df1"),
  superAdmin: {},
  user_management: { acc_permissions: {} },
  __v: 0
}
found save {
  _id: new ObjectId("65140fdd48d3d0b650b16df1"),
  superAdmin: {},
  user_management: { acc_permissions: {} },
  __v: 0,
  settings: {}
}

Reproduction Repository & Branch

PS: the final code in #883 (comment) was originally not complete, so i updated it (sorry)

@hasezoey
Copy link
Member

@hasezoey hello, I use minimize: false, so that mongoose does not remove empty object. Regarding everything discussed above -> it does not work(( I mean empty object schema or setter for empty object. To be precise user_management. It's always saved as an empty object (even if I pass acc_permissions or other props). Seems to be minimize: false is not propagated to nested object (user_managemen) on user permissions. FYI I tried adding this option to UserManagement and it did not work as well.

i dont know how you tested, so you might have run into Automattic/mongoose#13782 (Automattic/mongoose#13843)

@wasya243
Copy link
Author

@hasezoey thanks, seems to be working, I believe I messed things up when using type property...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Qustions about how to use stuff
Projects
None yet
Development

No branches or pull requests

2 participants