Typegraphql + TypeORM: lưu / cập nhật một mảng thực thể

Oct 05 2020

Tôi có một máy chủ graphql và một rolebảng, và tôi muốn lưu nhiều vai trò trong một đột biến.

Tôi đã tìm kiếm rất nhiều nhưng không tìm thấy gì.

Làm thế nào tôi có thể làm một cái gì đó như:

mutation {
  addRoles (roles: [
    {
      name: "role1",
      description: "role 1"
    },
    {
      name: "role2",
      description: "role 2"
    },
    ...
  ])
}

Nói cách khác, làm thế nào để thực hiện addRolesvà updateRolesgiải quyết?

Vòng lặp for có phải là lựa chọn duy nhất không? Có thể lưu tất cả các vai trò trong một lệnh gọi DB không?

Các rolemô hình:

@Entity("role")
@ObjectType()
export class Role extends BaseEntity {
  @Field((type) => Number)
  @PrimaryGeneratedColumn()
  readonly id!: number;

  @Field()
  @Column({ length: 64 })
  name!: string;

  @Field({ nullable: true })
  @Column({ length: 512, nullable: true })
  description!: string;
}

Và thêm và cập nhật trình giải quyết:

@Resolver((of) => Role)
export class RoleResolver {

  @Mutation((returns) => Boolean)
  async addRole(
    @Arg("role") role: AddRoleInput
  ): Promise<Boolean> {
    const roleExists = await Role.count({ name: role.name });
    if (roleExists > 0)
      throw new Error(`Role with name "${role.name}" already exists!`);

    const newRole = Role.create(role);
    await newRole.save();
    return true;
  }

  @Mutation((returns) => Boolean)
  async updateRole(
    @Arg("role") role: UpdateRoleInput
  ): Promise<Boolean> {
    const oldRole = await Role.findOneOrFail(role.id);
    Object.assign(oldRole, role);
    await oldRole.save();
    return true;
  }
}

Và AddRoleInputvàUpdateRoleInput


@InputType({ description: "New Role Argument" })
export class AddRoleInput implements Partial<Role> {
  @Field()
  name!: string;

  @Field({ nullable: true })
  description?: string;
}

@InputType({ description: "Update Role Argument" })
export class UpdateRoleInput implements Partial<Role> {
  @Field()
  id!: number;

  @Field()
  name!: string;

  @Field({ nullable: true })
  description?: string;
}

Trả lời

digita1-anal0g Oct 07 2020 at 04:08

Ý chính của những gì bạn cần làm là xác định một addRolestrường trên loại Mutation trong lược đồ của bạn. Ví dụ

export const RoleSchema = gql`
  type Role {
    id: Int
    # Other fields omitted for brevity
  }

  extend type Mutation {
    # This should already exist
    addRole(role: AddRoleInput!): Role!

    # To accept multiple Input Types, use the List construct
    addRoles(roles: [AddRoleInput!]!): [Role!]
  }
`;

Sau đó, xác định addRolestrong trình phân giải của bạn và gọi API thích hợp.

JunmingWang Oct 09 2020 at 02:01

Tôi đã cố gắng tìm ra câu trả lời bằng cách thử và sai. Tôi sẽ đăng nó ở đây trong trường hợp ai đó gặp vấn đề tương tự:

@Resolver((of) => Role)
export class RoleResolver {

  @Mutation((returns) => Boolean)
  async addRoles(
    @Arg("roles", type => [AddRoleInput]) roles: AddRoleInput[]
  ): Promise<Boolean> {

    // also checks at front
    const roleExists = await Role.count({
      name: In(roles.map((role) => role.name)),
    });
    if (roleExists > 0)
      throw new Error(`Role name conflict!`);
 
    const newRoles = []
    for (let i=0, i < roles.length, i++) {
        const newRole = Role.create(roles[i]);
        newRoles.push(newRole);
    }

    // this is the solution
    // turns out an entity class can be used to save instances
    // failed to found this in the docs though
    await Role.save(newRoles);

    return true;
  }
...
}

Tôi sẽ giữ tiền thưởng mở trong trường hợp có câu trả lời tốt hơn.