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

Update relation on update #32

Open
nmahren opened this issue Oct 6, 2023 · 3 comments
Open

Update relation on update #32

nmahren opened this issue Oct 6, 2023 · 3 comments

Comments

@nmahren
Copy link

nmahren commented Oct 6, 2023

Maybe this is an issue of my misunderstanding of Prisma principles, but why can't I updated a related element via the update dto? Since Prisma doesn't support composite types, I am using a nested structure with models and would like to update them via one dto. Could you implement an @DtoRelationCanUpdateOnUpdate annotation?

@Brakebein
Copy link
Owner

Currently, the generator follows the pattern how you can create/connect/disconnect a relation in Prisma. If being consistent, @DtoRelationCanUpdateOnUpdate annotation would result in something like this:

posts: {
  update: {
    where: {
      id: 9,
    },
    data: {
      title: 'My updated title',
    },
  },
},

https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#update-a-specific-related-record

But these update queries can be quite diverse.

However, this is probably not the kind of nested structure you have in mind like it would be with composite types (which are supported by Prisma if using MongoDB).

In our projects, we usually created some custom DTOs, for example:

export class UpdateUserWithCompanyDto extends UpdateUserDto {
  @ValidateNested()
  company: UpdateCompanyDto;
}

I don't know about your use case. Maybe you need to share an example of yours.

@dariusj18
Copy link

I was able to accomplish this by adding DtoRelationCanUpdateOnUpdate and DtoRelationCanUpsertOnUpdate annotations and then adding the following to the generateRelationInput function.

This was on top of the repo taht this one was forked off of, so I am not sure how this works with the other changes made to this repo

  if (isAnnotatedWith(field, canUpdateAnnotation)) {
    const preAndPostfixedName = t.updateDtoName(field.type);
    apiExtraModels.push(preAndPostfixedName);
    const modelToImportFrom = allModels.find(({ name }) => name === field.type);

    if (!modelToImportFrom)
      throw new Error(
        `related model '${field.type}' for '${model.name}.${field.name}' not found`
      );

    imports.push({
      from: slash(
        `${getRelativePath(model.output.dto, modelToImportFrom.output.dto)}${
          path.sep
        }${t.updateDtoFilename(field.type)}`
      ),
      destruct: [preAndPostfixedName],
    });

    relationInputClassProps.push({
      name: 'update',
      type: preAndPostfixedName,
    });
  }

  if (isAnnotatedWith(field, canUpsertAnnotation)) {
    const createPreAndPostfixedName = t.createDtoName(field.type);
    const updatePreAndPostfixedName = t.updateDtoName(field.type);
    apiExtraModels.push(createPreAndPostfixedName);
    apiExtraModels.push(updatePreAndPostfixedName);
    const modelToImportFrom = allModels.find(({ name }) => name === field.type);

    if (!modelToImportFrom)
      throw new Error(
        `related model '${field.type}' for '${model.name}.${field.name}' not found`
      );

    imports.push({
      from: slash(
        `${getRelativePath(model.output.dto, modelToImportFrom.output.dto)}${
          path.sep
        }${t.createDtoFilename(field.type)}`
      ),
      destruct: [createPreAndPostfixedName],
    });

    imports.push({
      from: slash(
        `${getRelativePath(model.output.dto, modelToImportFrom.output.dto)}${
          path.sep
        }${t.updateDtoFilename(field.type)}`
      ),
      destruct: [updatePreAndPostfixedName],
    });

    relationInputClassProps.push({
      name: 'upsert',
      type: `{ create: ${createPreAndPostfixedName}, update: ${updatePreAndPostfixedName} }`,
    });
  }

Brakebein added a commit that referenced this issue Mar 7, 2025
fix ApiProperty nullable in ConnectDTOss
@Brakebein
Copy link
Owner

Thanks a lot! I have finally tested your code and it works so far.

However, there are two points i still have doubts about:

  1. This only applies to "-to-one" relations. For "-to-many" relations, the resulting object more nested and complex including where and data property as pointed out in the comment above. Well, it could be limited only to "-to-one" relations and stated in the docs.

  2. To be consistent with the rest of the generated output, it would also need ApiProperty and class-validator decorators. This makes it even more complex for those heavily nested objects since each level needs to be defined as class by its own (at least for upsert we would need an extra class).

So, I added @DtoRelationCanUpdateOnUpdate for "-to-one" relations, which is the most simple addition. All other cases are too complex for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants