mirror of
https://github.com/strapi/strapi.git
synced 2025-11-11 07:39:16 +00:00
chore: create updateEntry
This commit is contained in:
parent
5e5bcf8c8f
commit
2b548ef558
@ -137,11 +137,9 @@ describe('history-version service', () => {
|
|||||||
contentType: {
|
contentType: {
|
||||||
uid: 'api::article.article',
|
uid: 'api::article.article',
|
||||||
},
|
},
|
||||||
args: [
|
params: {
|
||||||
{
|
locale: 'fr',
|
||||||
locale: 'fr',
|
},
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const next = jest.fn((context) => ({ ...context, documentId: 'document-id' }));
|
const next = jest.fn((context) => ({ ...context, documentId: 'document-id' }));
|
||||||
@ -154,7 +152,8 @@ describe('history-version service', () => {
|
|||||||
expect(next).toHaveBeenCalled();
|
expect(next).toHaveBeenCalled();
|
||||||
|
|
||||||
// Ensure we're only storing the data we need in the database
|
// Ensure we're only storing the data we need in the database
|
||||||
expect(mockFindOne).toHaveBeenLastCalledWith('document-id', {
|
expect(mockFindOne).toHaveBeenLastCalledWith({
|
||||||
|
documentId: 'document-id',
|
||||||
locale: 'fr',
|
locale: 'fr',
|
||||||
populate: {
|
populate: {
|
||||||
component: {
|
component: {
|
||||||
|
|||||||
@ -308,7 +308,7 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
|
|||||||
if ('documentId' in entry) {
|
if ('documentId' in entry) {
|
||||||
relatedEntry = await strapi
|
relatedEntry = await strapi
|
||||||
.documents(attributeSchema.target)
|
.documents(attributeSchema.target)
|
||||||
.findOne(entry.documentId, { locale: entry.locale || undefined });
|
.findOne({ documentId: entry.documentId, locale: entry.locale || undefined });
|
||||||
}
|
}
|
||||||
// For media assets, only the id is available, double check that we have it
|
// For media assets, only the id is available, double check that we have it
|
||||||
} else if ('id' in entry) {
|
} else if ('id' in entry) {
|
||||||
|
|||||||
@ -105,7 +105,8 @@ describe('Default Service', () => {
|
|||||||
|
|
||||||
expect(dbInstance.findOne).toHaveBeenCalledWith();
|
expect(dbInstance.findOne).toHaveBeenCalledWith();
|
||||||
|
|
||||||
expect(documentService.update).toHaveBeenCalledWith(1, {
|
expect(documentService.update).toHaveBeenCalledWith({
|
||||||
|
documentId: 1,
|
||||||
data: input,
|
data: input,
|
||||||
status: 'published',
|
status: 'published',
|
||||||
});
|
});
|
||||||
@ -137,7 +138,7 @@ describe('Default Service', () => {
|
|||||||
|
|
||||||
expect(dbInstance.findOne).toHaveBeenCalledWith();
|
expect(dbInstance.findOne).toHaveBeenCalledWith();
|
||||||
|
|
||||||
expect(documentService.delete).toHaveBeenCalledWith(1, { status: 'published' });
|
expect(documentService.delete).toHaveBeenCalledWith({ documentId: 1, status: 'published' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -19,8 +19,6 @@ type ComponentBody = {
|
|||||||
[key: string]: ComponentValue | DynamicZoneValue;
|
[key: string]: ComponentValue | DynamicZoneValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isDialectMySQL = () => strapi.db?.dialect.client === 'mysql';
|
|
||||||
|
|
||||||
function omitComponentData(
|
function omitComponentData(
|
||||||
contentType: Struct.ContentTypeSchema,
|
contentType: Struct.ContentTypeSchema,
|
||||||
data: Modules.EntityService.Params.Data.Input<Struct.ContentTypeSchema['uid']>
|
data: Modules.EntityService.Params.Data.Input<Struct.ContentTypeSchema['uid']>
|
||||||
@ -83,11 +81,9 @@ const createComponents = async <
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
||||||
const components = (await async.map(
|
const components: RepeatableComponentValue = await async.map(componentValue, (value: any) =>
|
||||||
componentValue,
|
createComponent(componentUID, value)
|
||||||
(value: any) => createComponent(componentUID, value),
|
);
|
||||||
{ concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity }
|
|
||||||
)) as RepeatableComponentValue;
|
|
||||||
|
|
||||||
componentBody[attributeName] = components.map(({ id }) => {
|
componentBody[attributeName] = components.map(({ id }) => {
|
||||||
return {
|
return {
|
||||||
@ -103,6 +99,7 @@ const createComponents = async <
|
|||||||
componentUID,
|
componentUID,
|
||||||
componentValue as Modules.EntityService.Params.Data.Input<UID.Component>
|
componentValue as Modules.EntityService.Params.Data.Input<UID.Component>
|
||||||
);
|
);
|
||||||
|
|
||||||
componentBody[attributeName] = {
|
componentBody[attributeName] = {
|
||||||
id: component.id,
|
id: component.id,
|
||||||
__pivot: {
|
__pivot: {
|
||||||
@ -140,8 +137,7 @@ const createComponents = async <
|
|||||||
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
||||||
componentBody[attributeName] = await async.map(
|
componentBody[attributeName] = await async.map(
|
||||||
dynamiczoneValues,
|
dynamiczoneValues,
|
||||||
createDynamicZoneComponents,
|
createDynamicZoneComponents
|
||||||
{ concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -200,11 +196,9 @@ const updateComponents = async <
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
||||||
const components = (await async.map(
|
const components: RepeatableComponentValue = await async.map(componentValue, (value: any) =>
|
||||||
componentValue,
|
updateOrCreateComponent(componentUID, value)
|
||||||
(value: any) => updateOrCreateComponent(componentUID, value),
|
);
|
||||||
{ concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity }
|
|
||||||
)) as RepeatableComponentValue;
|
|
||||||
|
|
||||||
componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => {
|
componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => {
|
||||||
return {
|
return {
|
||||||
@ -235,21 +229,17 @@ const updateComponents = async <
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
||||||
componentBody[attributeName] = await async.map(
|
componentBody[attributeName] = await async.map(dynamiczoneValues, async (value: any) => {
|
||||||
dynamiczoneValues,
|
const { id } = await updateOrCreateComponent(value.__component, value);
|
||||||
async (value: any) => {
|
|
||||||
const { id } = await updateOrCreateComponent(value.__component, value);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
__component: value.__component,
|
__component: value.__component,
|
||||||
__pivot: {
|
__pivot: {
|
||||||
field: attributeName,
|
field: attributeName,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
{ concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,20 +369,14 @@ const deleteComponents = async <TUID extends UID.Schema, TEntity extends Data.En
|
|||||||
if (attribute.type === 'component') {
|
if (attribute.type === 'component') {
|
||||||
const { component: componentUID } = attribute;
|
const { component: componentUID } = attribute;
|
||||||
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
||||||
await async.map(
|
await async.map(_.castArray(value), (subValue: any) =>
|
||||||
_.castArray(value),
|
deleteComponent(componentUID, subValue)
|
||||||
(subValue: any) => deleteComponent(componentUID, subValue),
|
|
||||||
{
|
|
||||||
concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// delete dynamic zone components
|
// delete dynamic zone components
|
||||||
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
|
||||||
await async.map(
|
await async.map(_.castArray(value), (subValue: any) =>
|
||||||
_.castArray(value),
|
deleteComponent(subValue.__component, subValue)
|
||||||
(subValue: any) => deleteComponent(subValue.__component, subValue),
|
|
||||||
{ concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity }
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,8 +453,21 @@ const deleteComponent = async <TUID extends UID.Component>(
|
|||||||
await strapi.db.query(uid).delete({ where: { id: componentToDelete.id } });
|
await strapi.db.query(uid).delete({ where: { id: componentToDelete.id } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const assignComponentData = <TUID extends UID.ContentType>(
|
||||||
|
data: Modules.EntityService.Params.Data.Input<TUID>,
|
||||||
|
componentData: ComponentBody,
|
||||||
|
{
|
||||||
|
contentType,
|
||||||
|
}: {
|
||||||
|
contentType: Schema.ContentType<TUID>;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
return Object.assign(omitComponentData(contentType, data), componentData);
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
omitComponentData,
|
omitComponentData,
|
||||||
|
assignComponentData,
|
||||||
getComponents,
|
getComponents,
|
||||||
createComponents,
|
createComponents,
|
||||||
updateComponents,
|
updateComponents,
|
||||||
|
|||||||
@ -29,11 +29,10 @@ const createEntriesService = (uid: UID.ContentType) => {
|
|||||||
|
|
||||||
// Component handling
|
// Component handling
|
||||||
const componentData = await components.createComponents(uid, validData);
|
const componentData = await components.createComponents(uid, validData);
|
||||||
const contentTypeWithoutComponentData = components.omitComponentData(contentType, validData);
|
const dataWithComponents = components.assignComponentData(validData, componentData, {
|
||||||
const entryData = applyTransforms(
|
contentType,
|
||||||
Object.assign(contentTypeWithoutComponentData, componentData) as any,
|
});
|
||||||
{ contentType }
|
const entryData = applyTransforms(dataWithComponents, { contentType });
|
||||||
);
|
|
||||||
|
|
||||||
const doc = await strapi.db.query(uid).create({ ...query, data: entryData });
|
const doc = await strapi.db.query(uid).create({ ...query, data: entryData });
|
||||||
|
|
||||||
@ -48,9 +47,35 @@ const createEntriesService = (uid: UID.ContentType) => {
|
|||||||
await components.deleteComponents(uid, componentsToDelete as any, { loadComponents: false });
|
await components.deleteComponents(uid, componentsToDelete as any, { loadComponents: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateEntry(entryToUpdate: any, params = {} as any) {
|
||||||
|
const { data, ...restParams } = await transformParamsDocumentId(uid, params);
|
||||||
|
const query = transformParamsToQuery(uid, pickSelectionParams(restParams) as any); // select / populate
|
||||||
|
|
||||||
|
const validData = await entityValidator.validateEntityUpdate(
|
||||||
|
contentType,
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
isDraft: !params?.data?.publishedAt, // Always update the draft version
|
||||||
|
locale: params?.locale,
|
||||||
|
},
|
||||||
|
entryToUpdate
|
||||||
|
);
|
||||||
|
// Component handling
|
||||||
|
const componentData = await components.updateComponents(uid, entryToUpdate, validData as any);
|
||||||
|
const dataWithComponents = components.assignComponentData(validData, componentData, {
|
||||||
|
contentType,
|
||||||
|
});
|
||||||
|
const entryData = applyTransforms(dataWithComponents, { contentType });
|
||||||
|
|
||||||
|
return strapi.db
|
||||||
|
.query(uid)
|
||||||
|
.update({ ...query, where: { id: entryToUpdate.id }, data: entryData });
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
create: createEntry,
|
create: createEntry,
|
||||||
delete: deleteEntry,
|
delete: deleteEntry,
|
||||||
|
update: updateEntry,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -5,18 +5,15 @@ import { async, contentTypes as contentTypesUtils } from '@strapi/utils';
|
|||||||
import { wrapInTransaction, type RepositoryFactoryMethod } from './common';
|
import { wrapInTransaction, type RepositoryFactoryMethod } from './common';
|
||||||
import * as DP from './draft-and-publish';
|
import * as DP from './draft-and-publish';
|
||||||
import * as i18n from './internationalization';
|
import * as i18n from './internationalization';
|
||||||
import { transformParamsDocumentId } from './transform/id-transform';
|
|
||||||
|
|
||||||
import * as components from './components';
|
import * as components from './components';
|
||||||
import { createEntriesService } from './entries';
|
|
||||||
|
|
||||||
|
import { createEntriesService } from './entries';
|
||||||
import { pickSelectionParams } from './params';
|
import { pickSelectionParams } from './params';
|
||||||
import { applyTransforms } from './attributes';
|
|
||||||
import entityValidator from '../entity-validator';
|
|
||||||
import { createDocumentId } from '../../utils/transform-content-types-to-models';
|
import { createDocumentId } from '../../utils/transform-content-types-to-models';
|
||||||
import { getDeepPopulate } from './utils/populate';
|
import { getDeepPopulate } from './utils/populate';
|
||||||
import { transformData } from './transform/data';
|
import { transformData } from './transform/data';
|
||||||
import { transformParamsToQuery } from './transform/query';
|
import { transformParamsToQuery } from './transform/query';
|
||||||
|
import { transformParamsDocumentId } from './transform/id-transform';
|
||||||
|
|
||||||
export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
||||||
const contentType = strapi.contentType(uid);
|
const contentType = strapi.contentType(uid);
|
||||||
@ -167,7 +164,6 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
|||||||
const query = transformParamsToQuery(uid, pickSelectionParams(restParams || {}) as any);
|
const query = transformParamsToQuery(uid, pickSelectionParams(restParams || {}) as any);
|
||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
const model = strapi.contentType(uid);
|
|
||||||
// Find if document exists
|
// Find if document exists
|
||||||
const entryToUpdate = await strapi.db
|
const entryToUpdate = await strapi.db
|
||||||
.query(uid)
|
.query(uid)
|
||||||
@ -175,27 +171,7 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
|||||||
|
|
||||||
let updatedDraft = null;
|
let updatedDraft = null;
|
||||||
if (entryToUpdate) {
|
if (entryToUpdate) {
|
||||||
const validData = await entityValidator.validateEntityUpdate(
|
updatedDraft = await entries.update(entryToUpdate, queryParams);
|
||||||
model,
|
|
||||||
// @ts-expect-error we need type guard to assert that data has the valid type
|
|
||||||
data,
|
|
||||||
{
|
|
||||||
isDraft: !queryParams?.data?.publishedAt, // Always update the draft version
|
|
||||||
locale: queryParams?.locale,
|
|
||||||
},
|
|
||||||
entryToUpdate
|
|
||||||
);
|
|
||||||
|
|
||||||
// Component handling
|
|
||||||
const componentData = await updateComponents(entryToUpdate, validData as any);
|
|
||||||
const entryData = applyTransforms(
|
|
||||||
Object.assign(omitComponentData(validData), componentData as any),
|
|
||||||
{ contentType: model }
|
|
||||||
);
|
|
||||||
|
|
||||||
updatedDraft = await strapi.db
|
|
||||||
.query(uid)
|
|
||||||
.update({ ...query, where: { id: entryToUpdate.id }, data: entryData });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!updatedDraft) {
|
if (!updatedDraft) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user