mirror of
https://github.com/strapi/strapi.git
synced 2025-08-11 02:07:51 +00:00
Entity service tests
This commit is contained in:
parent
c4c570fe3b
commit
cc4b360d47
@ -53,7 +53,7 @@ import convertCustomFieldType from './utils/convert-custom-field-type';
|
||||
// TODO: move somewhere else
|
||||
import * as draftAndPublishSync from './migrations/draft-publish';
|
||||
|
||||
import type { Common, Shared } from './types';
|
||||
import type { Common, Schema, Shared } from './types';
|
||||
|
||||
/**
|
||||
* Resolve the working directories based on the instance options.
|
||||
@ -635,7 +635,11 @@ class Strapi {
|
||||
}
|
||||
}
|
||||
|
||||
getModel(uid: string) {
|
||||
getModel(uid: Common.UID.ContentType): Schema.ContentType;
|
||||
getModel(uid: Common.UID.Component): Schema.Component;
|
||||
getModel(
|
||||
uid: Common.UID.Component | Common.UID.ContentType
|
||||
): Schema.Component | Schema.ContentType {
|
||||
return (
|
||||
this.contentTypes[uid as Common.UID.ContentType] ||
|
||||
this.components[uid as Common.UID.Component]
|
||||
|
@ -1,12 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
const createEntityService = require('..');
|
||||
const entityValidator = require('../../entity-validator');
|
||||
import createEntityService from '..';
|
||||
import entityValidator from '../../entity-validator';
|
||||
|
||||
describe('Entity service triggers webhooks', () => {
|
||||
let instance;
|
||||
let instance: any;
|
||||
const eventHub = { emit: jest.fn() };
|
||||
let entity = { attr: 'value' };
|
||||
let entity: unknown = { attr: 'value' };
|
||||
|
||||
beforeAll(() => {
|
||||
const model = {
|
||||
@ -25,11 +23,11 @@ describe('Entity service triggers webhooks', () => {
|
||||
},
|
||||
},
|
||||
db: {
|
||||
transaction: (cb) => cb(),
|
||||
transaction: (cb: any) => cb(),
|
||||
query: () => ({
|
||||
count: () => 0,
|
||||
create: ({ data }) => data,
|
||||
update: ({ data }) => data,
|
||||
create: ({ data }: any) => data,
|
||||
update: ({ data }: any) => data,
|
||||
findOne: () => entity,
|
||||
findMany: () => [entity, entity],
|
||||
delete: () => ({}),
|
||||
@ -38,16 +36,16 @@ describe('Entity service triggers webhooks', () => {
|
||||
},
|
||||
eventHub,
|
||||
entityValidator,
|
||||
});
|
||||
} as any);
|
||||
|
||||
global.strapi = {
|
||||
getModel: () => model,
|
||||
};
|
||||
} as any;
|
||||
});
|
||||
|
||||
test('Emit event: Create', async () => {
|
||||
// Create entity
|
||||
await instance.create('test-model', { data: entity });
|
||||
await instance.create('api::test.test-model', { data: entity });
|
||||
|
||||
// Expect entry.create event to be emitted
|
||||
expect(eventHub.emit).toHaveBeenCalledWith('entry.create', {
|
||||
@ -61,7 +59,7 @@ describe('Entity service triggers webhooks', () => {
|
||||
|
||||
test('Emit event: Update', async () => {
|
||||
// Update entity
|
||||
await instance.update('test-model', 'entity-id', { data: entity });
|
||||
await instance.update('api::test.test-model', 'entity-id', { data: entity });
|
||||
|
||||
// Expect entry.update event to be emitted
|
||||
expect(eventHub.emit).toHaveBeenCalledWith('entry.update', {
|
||||
@ -75,7 +73,7 @@ describe('Entity service triggers webhooks', () => {
|
||||
|
||||
test('Emit event: Delete', async () => {
|
||||
// Delete entity
|
||||
await instance.delete('test-model', 'entity-id', {});
|
||||
await instance.delete('api::test.test-model', 'entity-id', {});
|
||||
|
||||
// Expect entry.create event to be emitted
|
||||
expect(eventHub.emit).toHaveBeenCalledWith('entry.delete', {
|
||||
@ -89,7 +87,7 @@ describe('Entity service triggers webhooks', () => {
|
||||
|
||||
test('Emit event: Delete Many', async () => {
|
||||
// Delete entity
|
||||
await instance.deleteMany('test-model', {});
|
||||
await instance.deleteMany('api::test.test-model', {});
|
||||
|
||||
// Expect entry.create event to be emitted
|
||||
expect(eventHub.emit).toHaveBeenCalledWith('entry.delete', {
|
||||
@ -106,7 +104,7 @@ describe('Entity service triggers webhooks', () => {
|
||||
test('Do not emit event when no deleted entity', async () => {
|
||||
entity = null;
|
||||
// Delete non existent entity
|
||||
await instance.delete('test-model', 'entity-id', {});
|
||||
await instance.delete('api::test.test-model', 'entity-id', {});
|
||||
|
||||
// Expect entry.create event to be emitted
|
||||
expect(eventHub.emit).toHaveBeenCalledTimes(0);
|
@ -1,15 +1,18 @@
|
||||
'use strict';
|
||||
import { EventEmitter } from 'events';
|
||||
import { errors } from '@strapi/utils';
|
||||
import createEntityService from '..';
|
||||
import entityValidator from '../../entity-validator';
|
||||
import createEventHub from '../../event-hub';
|
||||
import type { Schema, Utils } from '../../../types';
|
||||
import uploadFiles from '../../utils/upload-files';
|
||||
|
||||
jest.mock('bcryptjs', () => ({ hashSync: () => 'secret-password' }));
|
||||
|
||||
const { EventEmitter } = require('events');
|
||||
const { ValidationError } = require('@strapi/utils').errors;
|
||||
const createEntityService = require('..');
|
||||
const entityValidator = require('../../entity-validator');
|
||||
|
||||
jest.mock('../../utils/upload-files', () => jest.fn(() => Promise.resolve()));
|
||||
|
||||
describe('Entity service', () => {
|
||||
const eventHub = createEventHub();
|
||||
|
||||
global.strapi = {
|
||||
getModel: jest.fn(() => ({})),
|
||||
config: {
|
||||
@ -22,27 +25,28 @@ describe('Entity service', () => {
|
||||
allowedEvents: new Map([['ENTRY_CREATE', 'entry.create']]),
|
||||
addAllowedEvent: jest.fn(),
|
||||
},
|
||||
};
|
||||
} as any;
|
||||
|
||||
describe('Decorator', () => {
|
||||
test.each(['create', 'update', 'findMany', 'findOne', 'delete', 'count', 'findPage'])(
|
||||
test.each(['create', 'update', 'findMany', 'findOne', 'delete', 'count', 'findPage'] as const)(
|
||||
'Can decorate',
|
||||
async (method) => {
|
||||
const instance = createEntityService({
|
||||
strapi: global.strapi,
|
||||
db: {},
|
||||
eventHub: new EventEmitter(),
|
||||
db: {} as any,
|
||||
eventHub,
|
||||
entityValidator,
|
||||
});
|
||||
|
||||
const methodFn = jest.fn();
|
||||
const decorator = () => ({
|
||||
[method]: methodFn,
|
||||
});
|
||||
|
||||
instance.decorate(decorator);
|
||||
instance.decorate((old) => ({
|
||||
...old,
|
||||
[method]: methodFn,
|
||||
}));
|
||||
|
||||
const args = [{}, {}];
|
||||
await instance[method](...args);
|
||||
await (instance[method] as Utils.Function.Any)(...args);
|
||||
expect(methodFn).toHaveBeenCalled();
|
||||
}
|
||||
);
|
||||
@ -61,28 +65,30 @@ describe('Entity service', () => {
|
||||
|
||||
const fakeDB = {
|
||||
query: jest.fn(() => fakeQuery),
|
||||
transaction: (cb) => cb(),
|
||||
transaction: (cb: Utils.Function.Any) => cb(),
|
||||
};
|
||||
|
||||
const fakeStrapi = {
|
||||
...global.strapi,
|
||||
query: fakeQuery,
|
||||
getModel: jest.fn(() => {
|
||||
return { kind: 'singleType' };
|
||||
}),
|
||||
};
|
||||
|
||||
const instance = createEntityService({
|
||||
strapi: fakeStrapi,
|
||||
db: fakeDB,
|
||||
eventHub: new EventEmitter(),
|
||||
strapi: fakeStrapi as any,
|
||||
db: fakeDB as any,
|
||||
eventHub,
|
||||
entityValidator,
|
||||
});
|
||||
|
||||
const result = await instance.findMany('test-model');
|
||||
const result = await instance.findMany('api::test.test-model');
|
||||
|
||||
expect(fakeStrapi.getModel).toHaveBeenCalledTimes(1);
|
||||
expect(fakeStrapi.getModel).toHaveBeenCalledWith('test-model');
|
||||
expect(fakeStrapi.getModel).toHaveBeenCalledWith('api::test.test-model');
|
||||
|
||||
expect(fakeDB.query).toHaveBeenCalledWith('test-model');
|
||||
expect(fakeDB.query).toHaveBeenCalledWith('api::test.test-model');
|
||||
expect(fakeQuery.findOne).toHaveBeenCalledWith({});
|
||||
expect(result).toEqual(data);
|
||||
});
|
||||
@ -97,11 +103,14 @@ describe('Entity service', () => {
|
||||
})),
|
||||
findOne: jest.fn(),
|
||||
};
|
||||
const fakeModels = {};
|
||||
const fakeModels: Record<string, Schema.ContentType | Schema.Component> = {};
|
||||
|
||||
beforeAll(() => {
|
||||
global.strapi.getModel.mockImplementation((modelName) => fakeModels[modelName]);
|
||||
global.strapi.query.mockImplementation(() => fakeQuery);
|
||||
jest
|
||||
.mocked(global.strapi.getModel)
|
||||
.mockImplementation((modelName: string) => fakeModels[modelName] as any);
|
||||
|
||||
jest.mocked(global.strapi.query).mockImplementation(() => fakeQuery as any);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
@ -109,16 +118,16 @@ describe('Entity service', () => {
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
global.strapi.getModel.mockImplementation(() => ({}));
|
||||
jest.mocked(global.strapi.getModel).mockImplementation(() => ({} as any));
|
||||
});
|
||||
|
||||
describe('assign default values', () => {
|
||||
let instance;
|
||||
let instance: any;
|
||||
const entityUID = 'api::entity.entity';
|
||||
const relationUID = 'api::relation.relation';
|
||||
|
||||
beforeAll(() => {
|
||||
const fakeEntities = {
|
||||
const fakeEntities: Record<string, Record<string, unknown>> = {
|
||||
[relationUID]: {
|
||||
1: {
|
||||
id: 1,
|
||||
@ -138,9 +147,16 @@ describe('Entity service', () => {
|
||||
};
|
||||
|
||||
fakeModels[entityUID] = {
|
||||
modelType: 'contentType',
|
||||
uid: entityUID,
|
||||
kind: 'contentType',
|
||||
kind: 'collectionType',
|
||||
modelName: 'test-model',
|
||||
globalId: 'test-model',
|
||||
info: {
|
||||
singularName: 'entity',
|
||||
pluralName: 'entities',
|
||||
displayName: 'ENTITY',
|
||||
},
|
||||
options: {},
|
||||
attributes: {
|
||||
attrStringDefaultRequired: {
|
||||
@ -173,9 +189,17 @@ describe('Entity service', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
fakeModels[relationUID] = {
|
||||
uid: relationUID,
|
||||
kind: 'contentType',
|
||||
modelType: 'contentType',
|
||||
globalId: 'relation',
|
||||
info: {
|
||||
displayName: 'RELATION',
|
||||
singularName: 'relation',
|
||||
pluralName: 'relations',
|
||||
},
|
||||
kind: 'collectionType',
|
||||
modelName: 'relation',
|
||||
attributes: {
|
||||
Name: {
|
||||
@ -185,32 +209,43 @@ describe('Entity service', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const fakeQuery = (uid) => ({
|
||||
create: jest.fn(({ data }) => data),
|
||||
count: jest.fn(({ where }) => {
|
||||
return where.id.$in.filter((id) => Boolean(fakeEntities[uid][id])).length;
|
||||
}),
|
||||
});
|
||||
const fakeQuery = (uid: string) =>
|
||||
({
|
||||
create: jest.fn(({ data }) => data),
|
||||
count: jest.fn(({ where }) => {
|
||||
return where.id.$in.filter((id: string) => Boolean(fakeEntities[uid][id])).length;
|
||||
}),
|
||||
} as any);
|
||||
|
||||
const fakeDB = {
|
||||
transaction: (cb) => cb(),
|
||||
transaction: (cb: Utils.Function.Any) => cb(),
|
||||
query: jest.fn((uid) => fakeQuery(uid)),
|
||||
};
|
||||
} as any;
|
||||
|
||||
global.strapi.db = fakeDB;
|
||||
global.strapi = {
|
||||
...global.strapi,
|
||||
db: fakeDB,
|
||||
query: jest.fn((uid) => fakeQuery(uid)),
|
||||
} as any;
|
||||
|
||||
instance = createEntityService({
|
||||
strapi: global.strapi,
|
||||
db: fakeDB,
|
||||
eventHub: new EventEmitter(),
|
||||
eventHub,
|
||||
entityValidator,
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
global.strapi.db = {
|
||||
global.strapi = {
|
||||
...global.strapi,
|
||||
db: {
|
||||
query: jest.fn(() => fakeQuery),
|
||||
},
|
||||
query: jest.fn(() => fakeQuery),
|
||||
};
|
||||
} as any;
|
||||
});
|
||||
|
||||
test('should create record with all default attributes', async () => {
|
||||
const data = {};
|
||||
|
||||
@ -315,7 +350,7 @@ describe('Entity service', () => {
|
||||
|
||||
const res = instance.create(entityUID, { data });
|
||||
await expect(res).rejects.toThrowError(
|
||||
new ValidationError(
|
||||
new errors.ValidationError(
|
||||
`1 relation(s) of type api::relation.relation associated with this entity do not exist`
|
||||
)
|
||||
);
|
||||
@ -323,19 +358,24 @@ describe('Entity service', () => {
|
||||
});
|
||||
|
||||
describe('with files', () => {
|
||||
let instance;
|
||||
let instance: any;
|
||||
|
||||
beforeAll(() => {
|
||||
fakeModels['test-model'] = {
|
||||
uid: 'test-model',
|
||||
fakeModels['api::test.test-model'] = {
|
||||
uid: 'api::test.test-model',
|
||||
kind: 'collectionType',
|
||||
collectionName: 'test-model',
|
||||
info: {
|
||||
displayName: 'test-model',
|
||||
singularName: 'test-model',
|
||||
pluralName: 'test-models',
|
||||
},
|
||||
options: {},
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
},
|
||||
activity: {
|
||||
displayName: 'activity',
|
||||
type: 'component',
|
||||
repeatable: true,
|
||||
component: 'basic.activity',
|
||||
@ -343,12 +383,11 @@ describe('Entity service', () => {
|
||||
},
|
||||
modelType: 'contentType',
|
||||
modelName: 'test-model',
|
||||
globalId: 'test-model',
|
||||
};
|
||||
|
||||
fakeModels['basic.activity'] = {
|
||||
collectionName: 'components_basic_activities',
|
||||
info: {
|
||||
displayName: 'activity',
|
||||
},
|
||||
options: {},
|
||||
attributes: {
|
||||
docs: {
|
||||
@ -375,6 +414,7 @@ describe('Entity service', () => {
|
||||
getModel: jest.fn((modelName) => fakeModels[modelName]),
|
||||
query: jest.fn(() => fakeQuery),
|
||||
db: {
|
||||
...fakeDB,
|
||||
dialect: {
|
||||
client: 'sqlite',
|
||||
},
|
||||
@ -384,17 +424,17 @@ describe('Entity service', () => {
|
||||
global.strapi = {
|
||||
...global.strapi,
|
||||
...fakeStrapi,
|
||||
};
|
||||
} as any;
|
||||
|
||||
instance = createEntityService({
|
||||
strapi: global.strapi,
|
||||
db: fakeDB,
|
||||
eventHub: new EventEmitter(),
|
||||
eventHub,
|
||||
entityValidator,
|
||||
});
|
||||
} as any);
|
||||
});
|
||||
test('should create record with attached files', async () => {
|
||||
const uploadFiles = require('../../utils/upload-files');
|
||||
|
||||
test.only('should create record with attached files', async () => {
|
||||
const data = {
|
||||
name: 'demoEvent',
|
||||
activity: [{ name: 'Powering the Aviation of the Future' }],
|
||||
@ -411,13 +451,13 @@ describe('Entity service', () => {
|
||||
|
||||
fakeQuery.findOne.mockResolvedValue({ id: 1, ...data });
|
||||
|
||||
await instance.create('test-model', { data, files });
|
||||
await instance.create('api::test.test-model', { data, files });
|
||||
|
||||
expect(global.strapi.getModel).toBeCalled();
|
||||
expect(uploadFiles).toBeCalled();
|
||||
expect(uploadFiles).toBeCalledTimes(1);
|
||||
expect(uploadFiles).toBeCalledWith(
|
||||
'test-model',
|
||||
'api::test.test-model',
|
||||
{
|
||||
id: 1,
|
||||
name: 'demoEvent',
|
||||
@ -439,12 +479,12 @@ describe('Entity service', () => {
|
||||
|
||||
describe('Update', () => {
|
||||
describe('assign default values', () => {
|
||||
let instance;
|
||||
let instance: any;
|
||||
|
||||
const entityUID = 'api::entity.entity';
|
||||
const relationUID = 'api::relation.relation';
|
||||
|
||||
const fakeEntities = {
|
||||
const fakeEntities: Record<string, Record<string, any>> = {
|
||||
[entityUID]: {
|
||||
0: {
|
||||
id: 0,
|
||||
@ -471,10 +511,12 @@ describe('Entity service', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const fakeModels = {
|
||||
const fakeModels: Record<string, Schema.ContentType> = {
|
||||
[entityUID]: {
|
||||
kind: 'collectionType',
|
||||
modelName: 'entity',
|
||||
globalId: 'entity',
|
||||
modelType: 'contentType',
|
||||
collectionName: 'entity',
|
||||
uid: entityUID,
|
||||
options: {},
|
||||
@ -496,8 +538,16 @@ describe('Entity service', () => {
|
||||
},
|
||||
},
|
||||
[relationUID]: {
|
||||
kind: 'contentType',
|
||||
kind: 'collectionType',
|
||||
globalId: 'entity',
|
||||
modelType: 'contentType',
|
||||
modelName: 'relation',
|
||||
uid: relationUID,
|
||||
info: {
|
||||
singularName: 'relation',
|
||||
pluralName: 'relations',
|
||||
displayName: 'RELATION',
|
||||
},
|
||||
attributes: {
|
||||
Name: {
|
||||
type: 'string',
|
||||
@ -509,11 +559,11 @@ describe('Entity service', () => {
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
const fakeQuery = (key) => ({
|
||||
const fakeQuery = (key: string) => ({
|
||||
findOne: jest.fn(({ where }) => fakeEntities[key][where.id]),
|
||||
count: jest.fn(({ where }) => {
|
||||
let ret = 0;
|
||||
where.id.$in.forEach((id) => {
|
||||
where.id.$in.forEach((id: string) => {
|
||||
const entity = fakeEntities[key][id];
|
||||
if (!entity) return;
|
||||
ret += 1;
|
||||
@ -534,18 +584,19 @@ describe('Entity service', () => {
|
||||
|
||||
global.strapi = {
|
||||
...global.strapi,
|
||||
getModel: jest.fn((uid) => {
|
||||
getModel: jest.fn((uid: string) => {
|
||||
return fakeModels[uid];
|
||||
}),
|
||||
query: jest.fn((key) => fakeQuery(key)),
|
||||
db: fakeDB,
|
||||
};
|
||||
} as any;
|
||||
|
||||
instance = createEntityService({
|
||||
strapi: global.strapi,
|
||||
db: fakeDB,
|
||||
eventHub: new EventEmitter(),
|
||||
entityValidator,
|
||||
});
|
||||
} as any);
|
||||
});
|
||||
|
||||
test(`should fail if the entity doesn't exist`, async () => {
|
||||
@ -587,7 +638,7 @@ describe('Entity service', () => {
|
||||
|
||||
const res = instance.update(entityUID, 0, { data });
|
||||
await expect(res).rejects.toThrowError(
|
||||
new ValidationError(
|
||||
new errors.ValidationError(
|
||||
`1 relation(s) of type api::relation.relation associated with this entity do not exist`
|
||||
)
|
||||
);
|
@ -34,6 +34,14 @@ export * from './types';
|
||||
|
||||
const { transformParamsToQuery } = convertQueryParams;
|
||||
|
||||
type Decoratable<T> = T & {
|
||||
decorate(
|
||||
decorator: (old: Types.EntityService) => Types.EntityService & {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
): void;
|
||||
};
|
||||
|
||||
type Context = {
|
||||
contentType: Schema.ContentType;
|
||||
};
|
||||
@ -89,11 +97,11 @@ const createDefaultImplementation = ({
|
||||
*/
|
||||
uploadFiles,
|
||||
|
||||
async wrapParams(options: any) {
|
||||
async wrapParams(options: any = {}) {
|
||||
return options;
|
||||
},
|
||||
|
||||
async wrapResult(result: any) {
|
||||
async wrapResult(result: any = {}) {
|
||||
return result;
|
||||
},
|
||||
|
||||
@ -237,10 +245,6 @@ const createDefaultImplementation = ({
|
||||
});
|
||||
const { data, files } = wrappedParams;
|
||||
|
||||
if (!data) {
|
||||
throw new Error('cannot update');
|
||||
}
|
||||
|
||||
const model = strapi.getModel(uid);
|
||||
|
||||
const entityToUpdate = await db.query(uid).findOne({ where: { id: entityId } });
|
||||
@ -455,7 +459,7 @@ export default (ctx: {
|
||||
db: Database;
|
||||
eventHub: EventHub;
|
||||
entityValidator: EntityValidator;
|
||||
}): Types.EntityService => {
|
||||
}): Decoratable<Types.EntityService> => {
|
||||
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
||||
ctx.strapi.webhookStore?.addAllowedEvent(key, value);
|
||||
});
|
||||
@ -507,5 +511,5 @@ export default (ctx: {
|
||||
return newService;
|
||||
});
|
||||
|
||||
return service as unknown as Types.EntityService;
|
||||
return service as unknown as Decoratable<Types.EntityService>;
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ import { uniqBy, castArray, isNil, isArray, mergeWith } from 'lodash';
|
||||
import { has, prop, isObject, isEmpty } from 'lodash/fp';
|
||||
import strapiUtils from '@strapi/utils';
|
||||
import validators from './validators';
|
||||
import { Common, Schema, Attribute, UID, Shared } from '../../types';
|
||||
import { Common, Schema, Attribute, Shared } from '../../types';
|
||||
import type * as Types from '../entity-service/types';
|
||||
|
||||
type CreateOrUpdate = 'creation' | 'update';
|
||||
@ -37,12 +37,12 @@ interface ValidatorContext {
|
||||
interface AttributeValidatorMetas {
|
||||
attr: Attribute.Any;
|
||||
updatedAttribute: { name: string; value: unknown };
|
||||
model: Schema.ContentType;
|
||||
model: Schema.ContentType | Schema.Component;
|
||||
entity?: Entity;
|
||||
}
|
||||
|
||||
interface ModelValidatorMetas {
|
||||
model: Schema.ContentType;
|
||||
model: Schema.ContentType | Schema.Component;
|
||||
data: Record<string, unknown>;
|
||||
entity?: Entity;
|
||||
}
|
||||
@ -299,7 +299,7 @@ const createModelValidator =
|
||||
const createValidateEntity = (createOrUpdate: CreateOrUpdate) => {
|
||||
return async <TUID extends Common.UID.ContentType, TData extends Types.Params.Data.Input<TUID>>(
|
||||
model: Shared.ContentTypes[TUID],
|
||||
data: TData | Partial<TData>,
|
||||
data: TData | Partial<TData> | undefined,
|
||||
options?: { isDraft?: boolean },
|
||||
entity?: Entity
|
||||
): Promise<TData> => {
|
||||
@ -312,11 +312,7 @@ const createValidateEntity = (createOrUpdate: CreateOrUpdate) => {
|
||||
}
|
||||
|
||||
const validator = createModelValidator(createOrUpdate)(
|
||||
{
|
||||
model,
|
||||
data,
|
||||
entity,
|
||||
},
|
||||
{ model, data, entity },
|
||||
{ isDraft: options?.isDraft ?? false }
|
||||
)
|
||||
.test('relations-test', 'check that all relations exist', async function (data) {
|
||||
@ -342,11 +338,11 @@ const createValidateEntity = (createOrUpdate: CreateOrUpdate) => {
|
||||
/**
|
||||
* Builds an object containing all the media and relations being associated with an entity
|
||||
*/
|
||||
const buildRelationsStore = ({
|
||||
const buildRelationsStore = <TUID extends Common.UID.ContentType | Common.UID.Component>({
|
||||
uid,
|
||||
data,
|
||||
}: {
|
||||
uid: Common.UID.ContentType | Common.UID.Component;
|
||||
uid: TUID;
|
||||
data: Record<string, unknown> | null;
|
||||
}): Record<string, ID[]> => {
|
||||
if (!uid) {
|
||||
@ -357,7 +353,7 @@ const buildRelationsStore = ({
|
||||
return {};
|
||||
}
|
||||
|
||||
const currentModel: Schema.ContentType = strapi.getModel(uid);
|
||||
const currentModel: Common.Schemas[TUID] = strapi.getModel(uid);
|
||||
|
||||
return Object.keys(currentModel.attributes).reduce((result, attributeName: string) => {
|
||||
const attribute = currentModel.attributes[attributeName];
|
||||
@ -470,7 +466,7 @@ const checkRelationsExist = async (relationsStore: Record<string, ID[]> = {}) =>
|
||||
for (const [key, value] of Object.entries(relationsStore)) {
|
||||
const evaluate = async () => {
|
||||
const uniqueValues = uniqBy(value, `id`);
|
||||
const count = await strapi.query(key as UID.ContentType).count({
|
||||
const count = await strapi.query(key as Common.UID.Schema).count({
|
||||
where: {
|
||||
id: {
|
||||
$in: uniqueValues.map((v) => v.id),
|
||||
@ -500,7 +496,7 @@ export interface EntityValidator {
|
||||
) => Promise<Types.Params.Data.Input<TUID>>;
|
||||
validateEntityUpdate: <TUID extends Common.UID.ContentType>(
|
||||
model: Shared.ContentTypes[TUID],
|
||||
data: Partial<Types.Params.Data.Input<TUID>>,
|
||||
data: Partial<Types.Params.Data.Input<TUID>> | undefined,
|
||||
options?: { isDraft?: boolean },
|
||||
entity?: Entity
|
||||
) => Promise<Types.Params.Data.Input<TUID>>;
|
||||
|
@ -9,7 +9,7 @@ export type Enumeration<TValues extends string[] = []> = Attribute.OfType<'enume
|
||||
EnumerationProperties<TValues> &
|
||||
// Options
|
||||
Attribute.ConfigurableOption &
|
||||
Attribute.DefaultOption<TValues> &
|
||||
Attribute.DefaultOption<TValues[number]> &
|
||||
Attribute.PrivateOption &
|
||||
Attribute.RequiredOption &
|
||||
Attribute.WritableOption &
|
||||
|
@ -8,7 +8,7 @@ export interface MediaProperties<
|
||||
TKind extends MediaKind | undefined = undefined,
|
||||
TMultiple extends Utils.Expression.BooleanValue = Utils.Expression.False
|
||||
> {
|
||||
allowedTypes?: TKind;
|
||||
allowedTypes?: TKind | TKind[];
|
||||
multiple?: TMultiple;
|
||||
}
|
||||
|
||||
|
@ -141,4 +141,8 @@ export interface SingleType extends ContentType {
|
||||
*/
|
||||
export interface Component extends Schema {
|
||||
modelType: 'component';
|
||||
|
||||
uid: Common.UID.Component;
|
||||
|
||||
category: string;
|
||||
}
|
||||
|
@ -195,8 +195,8 @@ const isTypedAttribute = (attribute: Attribute, type: string) => {
|
||||
*/
|
||||
const getContentTypeRoutePrefix = (contentType: Model) => {
|
||||
return isSingleType(contentType)
|
||||
? _.kebabCase(contentType.info.singularName)
|
||||
: _.kebabCase(contentType.info.pluralName);
|
||||
? _.kebabCase(contentType.info?.singularName)
|
||||
: _.kebabCase(contentType.info?.pluralName);
|
||||
};
|
||||
|
||||
export {
|
||||
|
@ -67,10 +67,10 @@ export type AnyAttribute =
|
||||
export type Kind = 'singleType' | 'collectionType';
|
||||
|
||||
export interface Model {
|
||||
modelType: 'contentType';
|
||||
modelType: 'contentType' | 'component';
|
||||
uid: string;
|
||||
kind: Kind;
|
||||
info: {
|
||||
kind?: Kind;
|
||||
info?: {
|
||||
displayName: string;
|
||||
singularName: string;
|
||||
pluralName: string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user