Skip to content

Commit 01187db

Browse files
authored
feat: discard drafts when enabling draft and publish on ct (#20257)
* feat: discard drafts when enabling draft and publish on ct * fix: migration tests
1 parent cffafe7 commit 01187db

File tree

3 files changed

+34
-62
lines changed

3 files changed

+34
-62
lines changed

packages/core/core/src/migrations/database/5.0.0-discard-drafts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type Knex = Parameters<Migration['up']>[0];
1212
* Versions with only a draft version will be ignored.
1313
* Only versions with a published version (which always have a draft version) will be discarded.
1414
*/
15-
async function* getBatchToDiscard({
15+
export async function* getBatchToDiscard({
1616
db,
1717
trx,
1818
uid,

packages/core/core/src/migrations/draft-publish.ts

Lines changed: 31 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import { contentTypes as contentTypesUtils } from '@strapi/utils';
1+
import { contentTypes as contentTypesUtils, async } from '@strapi/utils';
22
import { Schema } from '@strapi/types';
33

4+
import { getBatchToDiscard } from './database/5.0.0-discard-drafts';
5+
46
interface Input {
57
oldContentTypes: Record<string, Schema.ContentType>;
68
contentTypes: Record<string, Schema.ContentType>;
@@ -20,66 +22,36 @@ const enableDraftAndPublish = async ({ oldContentTypes, contentTypes }: Input) =
2022
}
2123

2224
// run the after content types migrations
23-
24-
for (const uid in contentTypes) {
25-
if (!oldContentTypes[uid]) {
26-
continue;
27-
}
28-
29-
const oldContentType = oldContentTypes[uid];
30-
const contentType = contentTypes[uid];
31-
32-
// if d&p was enabled set publishedAt to eq createdAt
33-
if (
34-
!contentTypesUtils.hasDraftAndPublish(oldContentType) &&
35-
contentTypesUtils.hasDraftAndPublish(contentType)
36-
) {
37-
const metadata = strapi.db.metadata.get(uid);
38-
39-
// Extract all scalar attributes to use in the insert query
40-
const attributes = Object.values(metadata.attributes).reduce((acc, attribute: any) => {
41-
if (['id'].includes(attribute.columnName)) {
42-
return acc;
43-
}
44-
45-
if (contentTypesUtils.isScalarAttribute(attribute)) {
46-
acc.push(attribute.columnName);
25+
return strapi.db.transaction(async (trx) => {
26+
for (const uid in contentTypes) {
27+
if (!oldContentTypes[uid]) {
28+
continue;
29+
}
30+
31+
const oldContentType = oldContentTypes[uid];
32+
const contentType = contentTypes[uid];
33+
34+
// if d&p was enabled set publishedAt to eq createdAt
35+
if (
36+
!contentTypesUtils.hasDraftAndPublish(oldContentType) &&
37+
contentTypesUtils.hasDraftAndPublish(contentType)
38+
) {
39+
const discardDraft = async (entry: { documentId: string; locale: string }) =>
40+
strapi
41+
.documents(uid as any)
42+
// Discard draft by referencing the documentId and locale
43+
.discardDraft({ documentId: entry.documentId, locale: entry.locale });
44+
45+
/**
46+
* Load a batch of entries (batched to prevent loading millions of rows at once ),
47+
* and discard them using the document service.
48+
*/
49+
for await (const batch of getBatchToDiscard({ db: strapi.db, trx, uid })) {
50+
await async.map(batch, discardDraft, { concurrency: 10 });
4751
}
48-
49-
return acc;
50-
}, [] as string[]);
51-
52-
/**
53-
* INSERT INTO tableName (columnName1, columnName2, columnName3, ...)
54-
* SELECT columnName1, columnName2, columnName3, ...
55-
* FROM tableName
56-
*/
57-
const qb = strapi.db?.getConnection();
58-
await qb
59-
// INSERT INTO tableName (columnName1, columnName2, columnName3, ...)
60-
.into(qb.raw(`${metadata.tableName} (${attributes.join(', ')})`))
61-
.insert((subQb: typeof qb) => {
62-
// SELECT columnName1, columnName2, columnName3, ...
63-
subQb
64-
.select(
65-
...attributes.map((att) => {
66-
// Override 'publishedAt' and 'updatedAt' attributes
67-
if (att === 'published_at') {
68-
return qb.raw('NULL as published_at');
69-
}
70-
71-
if (att === 'updated_at') {
72-
return qb.raw(`? as updated_at`, [new Date()]);
73-
}
74-
75-
return att;
76-
})
77-
)
78-
.from(metadata.tableName)
79-
.whereNotNull('published_at');
80-
});
52+
}
8153
}
82-
}
54+
});
8355
};
8456

8557
const disableDraftAndPublish = async ({ oldContentTypes, contentTypes }: Input) => {

tests/api/core/strapi/migrations/migration-draft-publish.test.api.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ describe('Migration - draft and publish', () => {
118118

119119
// Published dog should have a publishedAt value
120120
expect(draftDog.publishedAt).toBe(null);
121-
// Updated at value should be different
122-
expect(draftDog.updatedAt).not.toBe(publishedDog.updatedAt);
121+
// Updated at value should be the same
122+
expect(draftDog.updatedAt).toBe(publishedDog.updatedAt);
123123
});
124124

125125
data.dogs = sortDogs(dogs.filter((dog) => dog.publishedAt));

0 commit comments

Comments
 (0)