Skip to content

Commit

Permalink
CRUD Generator: Remove lastUpdatedAt argument from update mutations (
Browse files Browse the repository at this point in the history
…#1799)

This argument has the problem that it doesn't work well with multiple
forms that are submitted together, eg. with two forms in tabs that get
saved using a SaveBoundary.

We decided to simply drop this argument.

---------

Co-authored-by: Johannes Obermair <48853629+johnnyomair@users.noreply.github.com>
  • Loading branch information
nsams and johnnyomair authored Mar 7, 2024
1 parent 406e00c commit 0e6debb
Show file tree
Hide file tree
Showing 28 changed files with 60 additions and 105 deletions.
6 changes: 6 additions & 0 deletions .changeset/early-news-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@comet/cms-admin": major
"@comet/cms-api": major
---

CRUD Generator: Remove `lastUpdatedAt` argument from update mutations
4 changes: 2 additions & 2 deletions demo/admin/src/news/generated/NewsForm.gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export const createNewsMutation = gql`
`;

export const updateNewsMutation = gql`
mutation UpdateNews($id: ID!, $input: NewsUpdateInput!, $lastUpdatedAt: DateTime) {
updateNews(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt) {
mutation UpdateNews($id: ID!, $input: NewsUpdateInput!) {
updateNews(id: $id, input: $input) {
id
updatedAt
...NewsForm
Expand Down
2 changes: 1 addition & 1 deletion demo/admin/src/news/generated/NewsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export function NewsForm({ id }: FormProps): React.ReactElement {
}
await client.mutate<GQLUpdateNewsMutation, GQLUpdateNewsMutationVariables>({
mutation: updateNewsMutation,
variables: { id, input: output, lastUpdatedAt: data?.news?.updatedAt },
variables: { id, input: output },
});
} else {
const { data: mutationResponse } = await client.mutate<GQLCreateNewsMutation, GQLCreateNewsMutationVariables>({
Expand Down
4 changes: 2 additions & 2 deletions demo/admin/src/products/ProductForm.gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export const createProductMutation = gql`
`;

export const updateProductMutation = gql`
mutation UpdateProduct($id: ID!, $input: ProductUpdateInput!, $lastUpdatedAt: DateTime) {
updateProduct(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt) {
mutation UpdateProduct($id: ID!, $input: ProductUpdateInput!) {
updateProduct(id: $id, input: $input) {
id
updatedAt
...ProductFormManual
Expand Down
2 changes: 1 addition & 1 deletion demo/admin/src/products/ProductForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ function ProductForm({ id }: FormProps): React.ReactElement {
if (!id) throw new Error();
await client.mutate<GQLUpdateProductMutation, GQLUpdateProductMutationVariables>({
mutation: updateProductMutation,
variables: { id, input: output, lastUpdatedAt: data?.product.updatedAt },
variables: { id, input: output },
});
} else {
const { data: mutationResponse } = await client.mutate<GQLCreateProductMutation, GQLCreateProductMutationVariables>({
Expand Down
4 changes: 2 additions & 2 deletions demo/admin/src/products/ProductPriceForm.gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export const productPriceFormQuery = gql`
`;

export const updateProductPriceFormMutation = gql`
mutation ProductPriceFormUpdateProduct($id: ID!, $input: ProductUpdateInput!, $lastUpdatedAt: DateTime) {
updateProduct(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt) {
mutation ProductPriceFormUpdateProduct($id: ID!, $input: ProductUpdateInput!) {
updateProduct(id: $id, input: $input) {
id
updatedAt
...ProductPriceForm
Expand Down
2 changes: 1 addition & 1 deletion demo/admin/src/products/ProductPriceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function ProductPriceForm({ id }: FormProps): React.ReactElement {
};
await client.mutate<GQLProductPriceFormUpdateProductMutation, GQLProductPriceFormUpdateProductMutationVariables>({
mutation: updateProductPriceFormMutation,
variables: { id, input: output, lastUpdatedAt: data?.product.updatedAt },
variables: { id, input: output },
});
};

Expand Down
4 changes: 2 additions & 2 deletions demo/admin/src/products/categories/ProductCategoryForm.gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export const createProductCategoryMutation = gql`
`;

export const updateProductCategoryMutation = gql`
mutation ProductCategoryFormUpdateProductCategory($id: ID!, $input: ProductCategoryUpdateInput!, $lastUpdatedAt: DateTime) {
updateProductCategory(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt) {
mutation ProductCategoryFormUpdateProductCategory($id: ID!, $input: ProductCategoryUpdateInput!) {
updateProductCategory(id: $id, input: $input) {
id
updatedAt
...ProductCategoryForm
Expand Down
2 changes: 1 addition & 1 deletion demo/admin/src/products/categories/ProductCategoryForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function ProductCategoryForm({ id }: FormProps): React.ReactElement {
if (!id) throw new Error();
await client.mutate<GQLProductCategoryFormUpdateProductCategoryMutation, GQLProductCategoryFormUpdateProductCategoryMutationVariables>({
mutation: updateProductCategoryMutation,
variables: { id, input: output, lastUpdatedAt: data?.productCategory.updatedAt },
variables: { id, input: output },
});
} else {
const { data: mutationResponse } = await client.mutate<
Expand Down
4 changes: 2 additions & 2 deletions demo/admin/src/products/future/generated/ProductForm.gql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ export const createProductMutation = gql`
${productFormFragment}
`;
export const updateProductMutation = gql`
mutation UpdateProduct($id: ID!, $input: ProductUpdateInput!, $lastUpdatedAt: DateTime) {
updateProduct(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt) {
mutation UpdateProduct($id: ID!, $input: ProductUpdateInput!) {
updateProduct(id: $id, input: $input) {
id
updatedAt
...ProductFormDetails
Expand Down
2 changes: 1 addition & 1 deletion demo/admin/src/products/future/generated/ProductForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export function ProductForm({ id }: FormProps): React.ReactElement {
if (!id) throw new Error();
await client.mutate<GQLUpdateProductMutation, GQLUpdateProductMutationVariables>({
mutation: updateProductMutation,
variables: { id, input: output, lastUpdatedAt: data?.product.updatedAt },
variables: { id, input: output },
});
} else {
const { data: mutationResponse } = await client.mutate<GQLCreateProductMutation, GQLCreateProductMutationVariables>({
Expand Down
4 changes: 2 additions & 2 deletions demo/admin/src/products/generated/ProductForm.gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ export const createProductMutation = gql`
`;

export const updateProductMutation = gql`
mutation UpdateProduct($id: ID!, $input: ProductUpdateInput!, $lastUpdatedAt: DateTime) {
updateProduct(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt) {
mutation UpdateProduct($id: ID!, $input: ProductUpdateInput!) {
updateProduct(id: $id, input: $input) {
id
updatedAt
...ProductForm
Expand Down
2 changes: 1 addition & 1 deletion demo/admin/src/products/generated/ProductForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export function ProductForm({ id }: FormProps): React.ReactElement {
}
await client.mutate<GQLUpdateProductMutation, GQLUpdateProductMutationVariables>({
mutation: updateProductMutation,
variables: { id, input: output, lastUpdatedAt: data?.product?.updatedAt },
variables: { id, input: output },
});
} else {
const { data: mutationResponse } = await client.mutate<GQLCreateProductMutation, GQLCreateProductMutationVariables>({
Expand Down
4 changes: 2 additions & 2 deletions demo/admin/src/products/tags/ProductTagForm.gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export const createProductTagMutation = gql`
`;

export const updateProductTagMutation = gql`
mutation ProductTagFormUpdateProductTag($id: ID!, $input: ProductTagUpdateInput!, $lastUpdatedAt: DateTime) {
updateProductTag(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt) {
mutation ProductTagFormUpdateProductTag($id: ID!, $input: ProductTagUpdateInput!) {
updateProductTag(id: $id, input: $input) {
id
updatedAt
...ProductTagForm
Expand Down
2 changes: 1 addition & 1 deletion demo/admin/src/products/tags/ProductTagForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ function ProductTagForm({ id }: FormProps): React.ReactElement {
if (!id) throw new Error();
await client.mutate<GQLProductTagFormUpdateProductTagMutation, GQLProductTagFormUpdateProductTagMutationVariables>({
mutation: updateProductTagMutation,
variables: { id, input: output, lastUpdatedAt: data?.productTag.updatedAt },
variables: { id, input: output },
});
} else {
const { data: mutationResponse } = await client.mutate<
Expand Down
16 changes: 8 additions & 8 deletions demo/api/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -1098,29 +1098,29 @@ type Mutation {
moveDamFolders(folderIds: [ID!]!, targetFolderId: ID, scope: DamScopeInput!): [DamFolder!]!
deleteDamFolder(id: ID!): Boolean!
createNews(scope: NewsContentScopeInput!, input: NewsInput!): News!
updateNews(id: ID!, input: NewsUpdateInput!, lastUpdatedAt: DateTime): News!
updateNews(id: ID!, input: NewsUpdateInput!): News!
deleteNews(id: ID!): Boolean!
createNewsComment(newsId: ID!, input: NewsCommentInput!): NewsComment!
updateNewsComment(id: ID!, input: NewsCommentInput!, lastUpdatedAt: DateTime): NewsComment!
updateNewsComment(id: ID!, input: NewsCommentInput!): NewsComment!
deleteNewsComment(id: ID!): Boolean!
updateMainMenuItem(pageTreeNodeId: ID!, input: MainMenuItemInput!, lastUpdatedAt: DateTime): MainMenuItem!
saveFooter(scope: FooterContentScopeInput!, input: FooterInput!, lastUpdatedAt: DateTime): Footer!
saveFooter(scope: FooterContentScopeInput!, input: FooterInput!): Footer!
savePredefinedPage(id: ID!, input: PredefinedPageInput!, attachedPageTreeNodeId: ID!, lastUpdatedAt: DateTime): PredefinedPage!
triggerKubernetesCronJob(name: String!): KubernetesJob!
createProduct(input: ProductInput!): Product!
updateProduct(id: ID!, input: ProductUpdateInput!, lastUpdatedAt: DateTime): Product!
updateProduct(id: ID!, input: ProductUpdateInput!): Product!
deleteProduct(id: ID!): Boolean!
createProductCategory(input: ProductCategoryInput!): ProductCategory!
updateProductCategory(id: ID!, input: ProductCategoryUpdateInput!, lastUpdatedAt: DateTime): ProductCategory!
updateProductCategory(id: ID!, input: ProductCategoryUpdateInput!): ProductCategory!
deleteProductCategory(id: ID!): Boolean!
createProductTag(input: ProductTagInput!): ProductTag!
updateProductTag(id: ID!, input: ProductTagUpdateInput!, lastUpdatedAt: DateTime): ProductTag!
updateProductTag(id: ID!, input: ProductTagUpdateInput!): ProductTag!
deleteProductTag(id: ID!): Boolean!
createProductVariant(product: ID!, input: ProductVariantInput!): ProductVariant!
updateProductVariant(id: ID!, input: ProductVariantUpdateInput!, lastUpdatedAt: DateTime): ProductVariant!
updateProductVariant(id: ID!, input: ProductVariantUpdateInput!): ProductVariant!
deleteProductVariant(id: ID!): Boolean!
createManufacturer(input: ManufacturerInput!): Manufacturer!
updateManufacturer(id: ID!, input: ManufacturerUpdateInput!, lastUpdatedAt: DateTime): Manufacturer!
updateManufacturer(id: ID!, input: ManufacturerUpdateInput!): Manufacturer!
deleteManufacturer(id: ID!): Boolean!
}

Expand Down
17 changes: 6 additions & 11 deletions demo/api/src/footer/generated/footer.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file has been generated by comet api-generator.
// You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment.
import { RequiredPermission, validateNotModified } from "@comet/cms-api";
import { RequiredPermission } from "@comet/cms-api";
import { InjectRepository } from "@mikro-orm/nestjs";
import { EntityManager, EntityRepository } from "@mikro-orm/postgresql";
import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
Expand Down Expand Up @@ -33,7 +33,6 @@ export class FooterResolver {
async saveFooter(
@Args("scope", { type: () => FooterContentScope }) scope: FooterContentScope,
@Args("input", { type: () => FooterInput }) input: FooterInput,
@Args("lastUpdatedAt", { type: () => Date, nullable: true }) lastUpdatedAt?: Date,
): Promise<Footer> {
let footer = await this.repository.findOne({ scope });

Expand All @@ -42,17 +41,13 @@ export class FooterResolver {
...input,
scope,
});
} else if (lastUpdatedAt) {
if (lastUpdatedAt) {
validateNotModified(footer, lastUpdatedAt);
}

footer.assign({
...input,
content: input.content.transformToBlockData(),
});
}

footer.assign({
...input,
content: input.content.transformToBlockData(),
});

await this.entityManager.flush();

return footer;
Expand Down
6 changes: 1 addition & 5 deletions demo/api/src/news/generated/news.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file has been generated by comet api-generator.
// You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment.
import { AffectedEntity, extractGraphqlFields, RequiredPermission, validateNotModified } from "@comet/cms-api";
import { AffectedEntity, extractGraphqlFields, RequiredPermission } from "@comet/cms-api";
import { FindOptions } from "@mikro-orm/core";
import { InjectRepository } from "@mikro-orm/nestjs";
import { EntityManager, EntityRepository } from "@mikro-orm/postgresql";
Expand Down Expand Up @@ -92,12 +92,8 @@ export class NewsResolver {
async updateNews(
@Args("id", { type: () => ID }) id: string,
@Args("input", { type: () => NewsUpdateInput }) input: NewsUpdateInput,
@Args("lastUpdatedAt", { type: () => Date, nullable: true }) lastUpdatedAt?: Date,
): Promise<News> {
const news = await this.repository.findOneOrFail(id);
if (lastUpdatedAt) {
validateNotModified(news, lastUpdatedAt);
}

const { image: imageInput, content: contentInput, ...assignInput } = input;
news.assign({
Expand Down
5 changes: 0 additions & 5 deletions demo/api/src/news/news-comment.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,8 @@ export class NewsCommentResolver {
async updateNewsComment(
@Args("id", { type: () => ID }) id: string,
@Args("input", { type: () => NewsCommentInput }) input: NewsCommentInput,
@Args("lastUpdatedAt", { type: () => Date, nullable: true }) lastUpdatedAt?: Date,
): Promise<NewsComment> {
const newsComment = await this.newsCommentRepository.findOneOrFail(id);
console.log(lastUpdatedAt);
if (lastUpdatedAt) {
//validateNotModified(newsComment, lastUpdatedAt);
}
newsComment.assign({
...input,
});
Expand Down
6 changes: 1 addition & 5 deletions demo/api/src/products/generated/manufacturer.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file has been generated by comet api-generator.
// You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment.
import { AffectedEntity, RequiredPermission, validateNotModified } from "@comet/cms-api";
import { AffectedEntity, RequiredPermission } from "@comet/cms-api";
import { FindOptions } from "@mikro-orm/core";
import { InjectRepository } from "@mikro-orm/nestjs";
import { EntityManager, EntityRepository } from "@mikro-orm/postgresql";
Expand Down Expand Up @@ -62,12 +62,8 @@ export class ManufacturerResolver {
async updateManufacturer(
@Args("id", { type: () => ID }) id: string,
@Args("input", { type: () => ManufacturerUpdateInput }) input: ManufacturerUpdateInput,
@Args("lastUpdatedAt", { type: () => Date, nullable: true }) lastUpdatedAt?: Date,
): Promise<Manufacturer> {
const manufacturer = await this.repository.findOneOrFail(id);
if (lastUpdatedAt) {
validateNotModified(manufacturer, lastUpdatedAt);
}

manufacturer.assign({
...input,
Expand Down
6 changes: 1 addition & 5 deletions demo/api/src/products/generated/product-category.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file has been generated by comet api-generator.
// You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment.
import { AffectedEntity, extractGraphqlFields, RequiredPermission, validateNotModified } from "@comet/cms-api";
import { AffectedEntity, extractGraphqlFields, RequiredPermission } from "@comet/cms-api";
import { FindOptions } from "@mikro-orm/core";
import { InjectRepository } from "@mikro-orm/nestjs";
import { EntityManager, EntityRepository } from "@mikro-orm/postgresql";
Expand Down Expand Up @@ -81,12 +81,8 @@ export class ProductCategoryResolver {
async updateProductCategory(
@Args("id", { type: () => ID }) id: string,
@Args("input", { type: () => ProductCategoryUpdateInput }) input: ProductCategoryUpdateInput,
@Args("lastUpdatedAt", { type: () => Date, nullable: true }) lastUpdatedAt?: Date,
): Promise<ProductCategory> {
const productCategory = await this.repository.findOneOrFail(id);
if (lastUpdatedAt) {
validateNotModified(productCategory, lastUpdatedAt);
}

productCategory.assign({
...input,
Expand Down
6 changes: 1 addition & 5 deletions demo/api/src/products/generated/product-tag.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file has been generated by comet api-generator.
// You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment.
import { AffectedEntity, extractGraphqlFields, RequiredPermission, validateNotModified } from "@comet/cms-api";
import { AffectedEntity, extractGraphqlFields, RequiredPermission } from "@comet/cms-api";
import { FindOptions, Reference } from "@mikro-orm/core";
import { InjectRepository } from "@mikro-orm/nestjs";
import { EntityManager, EntityRepository } from "@mikro-orm/postgresql";
Expand Down Expand Up @@ -83,12 +83,8 @@ export class ProductTagResolver {
async updateProductTag(
@Args("id", { type: () => ID }) id: string,
@Args("input", { type: () => ProductTagUpdateInput }) input: ProductTagUpdateInput,
@Args("lastUpdatedAt", { type: () => Date, nullable: true }) lastUpdatedAt?: Date,
): Promise<ProductTag> {
const productTag = await this.repository.findOneOrFail(id);
if (lastUpdatedAt) {
validateNotModified(productTag, lastUpdatedAt);
}

const { products: productsInput, ...assignInput } = input;
productTag.assign({
Expand Down
6 changes: 1 addition & 5 deletions demo/api/src/products/generated/product-variant.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file has been generated by comet api-generator.
// You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment.
import { AffectedEntity, extractGraphqlFields, RequiredPermission, validateNotModified } from "@comet/cms-api";
import { AffectedEntity, extractGraphqlFields, RequiredPermission } from "@comet/cms-api";
import { FindOptions, Reference } from "@mikro-orm/core";
import { InjectRepository } from "@mikro-orm/nestjs";
import { EntityManager, EntityRepository } from "@mikro-orm/postgresql";
Expand Down Expand Up @@ -87,12 +87,8 @@ export class ProductVariantResolver {
async updateProductVariant(
@Args("id", { type: () => ID }) id: string,
@Args("input", { type: () => ProductVariantUpdateInput }) input: ProductVariantUpdateInput,
@Args("lastUpdatedAt", { type: () => Date, nullable: true }) lastUpdatedAt?: Date,
): Promise<ProductVariant> {
const productVariant = await this.repository.findOneOrFail(id);
if (lastUpdatedAt) {
validateNotModified(productVariant, lastUpdatedAt);
}

const { image: imageInput, ...assignInput } = input;
productVariant.assign({
Expand Down
6 changes: 1 addition & 5 deletions demo/api/src/products/generated/product.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file has been generated by comet api-generator.
// You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment.
import { AffectedEntity, extractGraphqlFields, RequiredPermission, validateNotModified } from "@comet/cms-api";
import { AffectedEntity, extractGraphqlFields, RequiredPermission } from "@comet/cms-api";
import { FindOptions, Reference } from "@mikro-orm/core";
import { InjectRepository } from "@mikro-orm/nestjs";
import { EntityManager, EntityRepository } from "@mikro-orm/postgresql";
Expand Down Expand Up @@ -139,12 +139,8 @@ export class ProductResolver {
async updateProduct(
@Args("id", { type: () => ID }) id: string,
@Args("input", { type: () => ProductUpdateInput }) input: ProductUpdateInput,
@Args("lastUpdatedAt", { type: () => Date, nullable: true }) lastUpdatedAt?: Date,
): Promise<Product> {
const product = await this.repository.findOneOrFail(id);
if (lastUpdatedAt) {
validateNotModified(product, lastUpdatedAt);
}

const {
colors: colorsInput,
Expand Down
6 changes: 3 additions & 3 deletions packages/admin/cms-admin/src/generator/future/generateForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ export function generateForm(
`;

gqlDocuments[`update${gqlType}Mutation`] = `
mutation Update${gqlType}($id: ID!, $input: ${gqlType}UpdateInput!, $lastUpdatedAt: DateTime) {
update${gqlType}(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt) {
mutation Update${gqlType}($id: ID!, $input: ${gqlType}UpdateInput!) {
update${gqlType}(id: $id, input: $input) {
id
updatedAt
...${fragmentName}
Expand Down Expand Up @@ -234,7 +234,7 @@ export function generateForm(
if (!id) throw new Error();
await client.mutate<GQLUpdate${gqlType}Mutation, GQLUpdate${gqlType}MutationVariables>({
mutation: update${gqlType}Mutation,
variables: { id, input: output, lastUpdatedAt: data?.${instanceGqlType}.updatedAt },
variables: { id, input: output },
});
} else {
const { data: mutationResponse } = await client.mutate<GQLCreate${gqlType}Mutation, GQLCreate${gqlType}MutationVariables>({
Expand Down
Loading

0 comments on commit 0e6debb

Please sign in to comment.