feat(dts): support models and contentTypes (#19604)

This commit is contained in:
markkaylor 2024-03-01 09:08:12 +01:00 committed by GitHub
parent ffe6a1f2e9
commit b0e5eb2398
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 175 additions and 35 deletions

View File

@ -59,6 +59,7 @@
"ws": "8.13.0"
},
"devDependencies": {
"@strapi/database": "workspace:*",
"@strapi/pack-up": "4.20.3",
"@types/fs-extra": "9.0.13",
"@types/jest": "29.5.2",

View File

@ -49,6 +49,13 @@ export const getContentTypes = (): {
bar: { uid: 'bar', attributes: { age: { type: 'number' } } },
});
/**
* Factory to get default strapi models test values
*/
export const getStrapiModels = () => {
return [{ uid: 'model::foo' }, { uid: 'model::bar' }];
};
/**
* Create a factory of readable streams (wrapped with a jest mock function)
*/

View File

@ -4,6 +4,7 @@ import {
getStrapiFactory,
getContentTypes,
setGlobalStrapi,
getStrapiModels,
} from '../../../../__tests__/test-utils';
afterEach(() => {
@ -140,15 +141,37 @@ describe('Local Strapi Source Destination', () => {
entity: { id: 9, age: 0 },
contentType: { uid: 'bar' },
},
{
entity: { id: 10, age: 0 },
model: { uid: 'model::foo' },
},
{
entity: { id: 11, age: 0 },
model: { uid: 'model::bar' },
},
];
const deleteMany = (uid: string) =>
jest.fn(async () => ({
count: entities.filter((entity) => entity.contentType.uid === uid).length,
count: entities.filter((entity) => {
if (entity.model) {
return entity.model.uid === uid;
}
return entity.contentType.uid === uid;
}).length,
}));
const findMany = (uid: string) => {
return jest.fn(async () => entities.filter((entity) => entity.contentType.uid === uid));
return jest.fn(async () =>
entities.filter((entity) => {
if (entity.model) {
return entity.model.uid === uid;
}
return entity.contentType.uid === uid;
})
);
};
const query = jest.fn((uid) => {
@ -164,6 +187,13 @@ describe('Local Strapi Source Destination', () => {
contentTypes: getContentTypes(),
query,
getModel,
get() {
return {
get() {
return getStrapiModels();
},
};
},
db: {
query,
transaction,

View File

@ -4,6 +4,7 @@ import {
getStrapiFactory,
getContentTypes,
setGlobalStrapi,
getStrapiModels,
} from '../../../../__tests__/test-utils';
import { IConfiguration } from '../../../../../types';
@ -36,6 +37,14 @@ const entities = [
entity: { id: 9, age: 0 },
contentType: { uid: 'bar' },
},
{
entity: { id: 10, age: 0 },
model: { uid: 'model::foo' },
},
{
entity: { id: 11, age: 0 },
model: { uid: 'model::bar' },
},
];
afterEach(() => {
@ -44,11 +53,25 @@ afterEach(() => {
const deleteMany = (uid: string) =>
jest.fn(async () => ({
count: entities.filter((entity) => entity.contentType.uid === uid).length,
count: entities.filter((entity) => {
if (entity.model) {
return entity.model.uid === uid;
}
return entity.contentType.uid === uid;
}).length,
}));
const findMany = (uid: string) => {
return jest.fn(async () => entities.filter((entity) => entity.contentType.uid === uid));
return jest.fn(async () =>
entities.filter((entity) => {
if (entity.model) {
return entity.model.uid === uid;
}
return entity.contentType.uid === uid;
})
);
};
const create = jest.fn((data) => data);
@ -64,12 +87,21 @@ const query = jest.fn((uid) => {
});
describe('Restore ', () => {
test('Should delete all contentTypes', async () => {
test('Should delete all models and contentTypes', async () => {
const strapi = getStrapiFactory({
contentTypes: getContentTypes(),
query,
getModel,
db: { query },
get() {
return {
get() {
return getStrapiModels();
},
};
},
db: {
query,
},
})();
setGlobalStrapi(strapi);
@ -83,7 +115,16 @@ describe('Restore ', () => {
contentTypes: getContentTypes(),
query,
getModel,
db: { query },
get() {
return {
get() {
return getStrapiModels();
},
};
},
db: {
query,
},
})();
setGlobalStrapi(strapi);
@ -96,6 +137,34 @@ describe('Restore ', () => {
expect(count).toBe(3);
});
test('Should only delete chosen model ', async () => {
const strapi = getStrapiFactory({
contentTypes: getContentTypes(),
query,
getModel,
get() {
return {
get() {
return getStrapiModels();
},
};
},
db: {
query,
},
})();
setGlobalStrapi(strapi);
const { count } = await deleteRecords(strapi, {
entities: {
include: ['model::foo'],
},
});
expect(count).toBe(1);
});
test('Should add core store data', async () => {
const strapi = getStrapiFactory({
contentTypes: getContentTypes(),

View File

@ -1,4 +1,5 @@
import type { LoadedStrapi, Schema } from '@strapi/types';
import type { LoadedStrapi, Schema, Common } from '@strapi/types';
import type { Model } from '@strapi/database';
import { ProviderTransferError } from '../../../../../errors/providers';
import * as queries from '../../../../queries';
@ -37,44 +38,75 @@ const deleteEntitiesRecords = async (
options: IRestoreOptions = {}
): Promise<IDeleteResults> => {
const { entities } = options;
const query = queries.entity.createEntityQuery(strapi);
const contentTypes = Object.values<Schema.ContentType>(
strapi.contentTypes as Record<string, Schema.ContentType>
);
const contentTypesToClear = contentTypes.filter((contentType) => {
let removeThisContentType = true;
const models = strapi.get('models').get() as Model[];
const contentTypes = Object.values(strapi.contentTypes) as Schema.ContentType[];
// include means "only include these types" so if it's not in here, it's not being included
if (entities?.include) {
removeThisContentType = entities.include.includes(contentType.uid);
}
const contentTypesToClear = contentTypes
.filter((contentType) => {
let removeThisContentType = true;
// if something is excluded, remove it. But lack of being excluded doesn't mean it's kept
if (entities?.exclude && entities.exclude.includes(contentType.uid)) {
removeThisContentType = false;
}
// include means "only include these types" so if it's not in here, it's not being included
if (entities?.include) {
removeThisContentType = entities.include.includes(contentType.uid);
}
if (entities?.filters) {
removeThisContentType = entities.filters.every((filter) => filter(contentType));
}
// if something is excluded, remove it. But lack of being excluded doesn't mean it's kept
if (entities?.exclude && entities.exclude.includes(contentType.uid)) {
removeThisContentType = false;
}
return removeThisContentType;
});
if (entities?.filters) {
removeThisContentType = entities.filters.every((filter) => filter(contentType));
}
const [results, updateResults] = useResults(
contentTypesToClear.map((contentType) => contentType.uid)
);
return removeThisContentType;
})
.map((contentType) => contentType.uid);
const deletePromises = contentTypesToClear.map(async (contentType) => {
const result = await query(contentType.uid).deleteMany(entities?.params);
const modelsToClear = models
.filter((model) => {
if (contentTypesToClear.includes(model.uid as Common.UID.ContentType)) {
return false;
}
let removeThisModel = true;
// include means "only include these types" so if it's not in here, it's not being included
if (entities?.include) {
removeThisModel = entities.include.includes(model.uid);
}
// if something is excluded, remove it. But lack of being excluded doesn't mean it's kept
if (entities?.exclude && entities.exclude.includes(model.uid)) {
removeThisModel = false;
}
return removeThisModel;
})
.map((model) => model.uid);
const [results, updateResults] = useResults([...contentTypesToClear, ...modelsToClear]);
const contentTypeQuery = queries.entity.createEntityQuery(strapi);
const contentTypePromises = contentTypesToClear.map(async (uid) => {
const result = await contentTypeQuery(uid).deleteMany(entities?.params);
if (result) {
updateResults(result.count || 0, contentType.uid);
updateResults(result.count || 0, uid);
}
});
await Promise.all(deletePromises);
const modelsPromises = modelsToClear.map(async (uid) => {
const result = await strapi.db.query(uid).deleteMany({});
if (result) {
updateResults(result.count || 0, uid);
}
});
await Promise.all([...contentTypePromises, ...modelsPromises]);
return results;
};

View File

@ -7060,6 +7060,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@strapi/data-transfer@workspace:packages/core/data-transfer"
dependencies:
"@strapi/database": "workspace:*"
"@strapi/logger": "npm:4.20.3"
"@strapi/pack-up": "npm:4.20.3"
"@strapi/types": "npm:4.20.3"
@ -7096,7 +7097,7 @@ __metadata:
languageName: unknown
linkType: soft
"@strapi/database@npm:4.20.3, @strapi/database@workspace:packages/core/database":
"@strapi/database@npm:4.20.3, @strapi/database@workspace:*, @strapi/database@workspace:packages/core/database":
version: 0.0.0-use.local
resolution: "@strapi/database@workspace:packages/core/database"
dependencies: