mirror of
				https://github.com/strapi/strapi.git
				synced 2025-11-04 03:43:34 +00:00 
			
		
		
		
	feat(dts): support models and contentTypes (#19604)
This commit is contained in:
		
							parent
							
								
									ffe6a1f2e9
								
							
						
					
					
						commit
						b0e5eb2398
					
				@ -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",
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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(),
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -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:
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user