mirror of
https://github.com/strapi/strapi.git
synced 2025-11-12 16:22:10 +00:00
Ts migration of the entity service
This commit is contained in:
parent
f018a3d19d
commit
4fdf1a0272
@ -1,5 +1,6 @@
|
|||||||
import transforms from './transforms';
|
import transforms from './transforms';
|
||||||
import type { Schema } from '../../../types';
|
import type { Common, Schema } from '../../../types';
|
||||||
|
import { Data } from '../types/params';
|
||||||
|
|
||||||
const applyTransforms = (
|
const applyTransforms = (
|
||||||
data: Record<string, unknown>,
|
data: Record<string, unknown>,
|
||||||
@ -9,9 +10,9 @@ const applyTransforms = (
|
|||||||
) => {
|
) => {
|
||||||
const { contentType } = context;
|
const { contentType } = context;
|
||||||
|
|
||||||
const entries = Object.entries(data);
|
for (const attributeName of Object.keys(data)) {
|
||||||
|
const value = data[attributeName];
|
||||||
|
|
||||||
for (const [attributeName, value] of entries) {
|
|
||||||
const attribute = contentType.attributes[attributeName];
|
const attribute = contentType.attributes[attributeName];
|
||||||
|
|
||||||
if (!attribute) {
|
if (!attribute) {
|
||||||
|
|||||||
@ -4,10 +4,10 @@ import bcrypt from 'bcryptjs';
|
|||||||
import type { Attribute } from '../../../types';
|
import type { Attribute } from '../../../types';
|
||||||
|
|
||||||
type Transforms = {
|
type Transforms = {
|
||||||
[key in Attribute.Kind]?: (
|
[TKind in Attribute.Kind]?: (
|
||||||
value: Attribute.GetValue<Attribute.Attribute<key>>,
|
value: Attribute.GetValue<Attribute.Attribute<TKind>>,
|
||||||
context: { attribute: Attribute.Attribute<key>; attributeName: string }
|
context: { attribute: Attribute.Attribute<TKind>; attributeName: string }
|
||||||
) => unknown;
|
) => Attribute.GetValue<Attribute.Attribute<TKind>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const transforms: Transforms = {
|
const transforms: Transforms = {
|
||||||
@ -22,6 +22,6 @@ const transforms: Transforms = {
|
|||||||
|
|
||||||
return bcrypt.hashSync(value, rounds);
|
return bcrypt.hashSync(value, rounds);
|
||||||
},
|
},
|
||||||
} as const;
|
};
|
||||||
|
|
||||||
export default transforms;
|
export default transforms;
|
||||||
|
|||||||
@ -38,8 +38,6 @@ type Context = {
|
|||||||
contentType: Schema.ContentType;
|
contentType: Schema.ContentType;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Entity = {};
|
|
||||||
|
|
||||||
const transformLoadParamsToQuery = (
|
const transformLoadParamsToQuery = (
|
||||||
uid: string,
|
uid: string,
|
||||||
field: string,
|
field: string,
|
||||||
@ -89,19 +87,22 @@ const createDefaultImplementation = ({
|
|||||||
eventHub: EventHub;
|
eventHub: EventHub;
|
||||||
entityValidator: EntityValidator;
|
entityValidator: EntityValidator;
|
||||||
}): types.EntityService => ({
|
}): types.EntityService => ({
|
||||||
|
/**
|
||||||
|
* Upload files utility
|
||||||
|
*/
|
||||||
uploadFiles,
|
uploadFiles,
|
||||||
|
|
||||||
async wrapParams(options) {
|
async wrapParams(options: any) {
|
||||||
return options;
|
return options;
|
||||||
},
|
},
|
||||||
|
|
||||||
async wrapResult(result) {
|
async wrapResult(result: any) {
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
async emitEvent(uid: Common.UID.Schema, event: string, entity: Entity) {
|
async emitEvent(uid, event: string, entity) {
|
||||||
// Ignore audit log events to prevent infinite loops
|
// Ignore audit log events to prevent infinite loops
|
||||||
if (uid === 'admin::audit-log') {
|
if (uid === ('admin::audit-log' as Common.UID.ContentType)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +116,7 @@ const createDefaultImplementation = ({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async findMany(uid: Common.UID.Schema, opts) {
|
async findMany(uid, opts) {
|
||||||
const { kind } = strapi.getModel(uid);
|
const { kind } = strapi.getModel(uid);
|
||||||
|
|
||||||
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' });
|
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' });
|
||||||
@ -131,7 +132,7 @@ const createDefaultImplementation = ({
|
|||||||
return this.wrapResult(entities, { uid, action: 'findMany' });
|
return this.wrapResult(entities, { uid, action: 'findMany' });
|
||||||
},
|
},
|
||||||
|
|
||||||
async findPage(uid: Common.UID.Schema, opts) {
|
async findPage(uid, opts) {
|
||||||
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findPage' });
|
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findPage' });
|
||||||
|
|
||||||
const query = transformParamsToQuery(uid, wrappedParams);
|
const query = transformParamsToQuery(uid, wrappedParams);
|
||||||
@ -183,16 +184,24 @@ const createDefaultImplementation = ({
|
|||||||
},
|
},
|
||||||
|
|
||||||
async create(uid, opts) {
|
async create(uid, opts) {
|
||||||
const wrappedParams = await this.wrapParams(opts, { uid, action: 'create' });
|
const wrappedParams = await this.wrapParams<
|
||||||
|
types.Params.Pick<Common.UID.ContentType, 'files' | 'data' | 'fields' | 'populate'>
|
||||||
|
>(opts, { uid, action: 'create' });
|
||||||
const { data, files } = wrappedParams;
|
const { data, files } = wrappedParams;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
throw new Error('cannot create');
|
||||||
|
}
|
||||||
|
|
||||||
const model = strapi.getModel(uid);
|
const model = strapi.getModel(uid);
|
||||||
|
|
||||||
const isDraft = contentTypesUtils.isDraft(data, model);
|
const isDraft = contentTypesUtils.isDraft(data, model);
|
||||||
const validData = await entityValidator.validateEntityCreation(model, data, { isDraft });
|
const validData = await entityValidator.validateEntityCreation(model, data, { isDraft });
|
||||||
|
|
||||||
// select / populate
|
// select / populate
|
||||||
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
const x = pickSelectionParams(wrappedParams);
|
||||||
|
|
||||||
|
const query = transformParamsToQuery(uid, x);
|
||||||
|
|
||||||
// TODO: wrap into transaction
|
// TODO: wrap into transaction
|
||||||
const componentData = await createComponents(uid, validData);
|
const componentData = await createComponents(uid, validData);
|
||||||
@ -353,7 +362,7 @@ const createDefaultImplementation = ({
|
|||||||
return entity;
|
return entity;
|
||||||
},
|
},
|
||||||
// FIXME: used only for the CM to be removed
|
// FIXME: used only for the CM to be removed
|
||||||
async deleteMany(uid: Common.UID.Schema, opts) {
|
async deleteMany(uid, opts) {
|
||||||
const wrappedParams = await this.wrapParams(opts, { uid, action: 'delete' });
|
const wrappedParams = await this.wrapParams(opts, { uid, action: 'delete' });
|
||||||
|
|
||||||
// select / populate
|
// select / populate
|
||||||
@ -383,7 +392,7 @@ const createDefaultImplementation = ({
|
|||||||
return deletedEntities;
|
return deletedEntities;
|
||||||
},
|
},
|
||||||
|
|
||||||
async load(uid: Common.UID.Schema, entity, field, params = {}) {
|
async load(uid, entity, field, params = {}) {
|
||||||
if (!_.isString(field)) {
|
if (!_.isString(field)) {
|
||||||
throw new Error(`Invalid load. Expected "${field}" to be a string`);
|
throw new Error(`Invalid load. Expected "${field}" to be a string`);
|
||||||
}
|
}
|
||||||
@ -395,7 +404,7 @@ const createDefaultImplementation = ({
|
|||||||
return this.wrapResult(loadedEntity, { uid, field, action: 'load' });
|
return this.wrapResult(loadedEntity, { uid, field, action: 'load' });
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadPages(uid: Common.UID.Schema, entity: Entity, field, params = {}, pagination = {}) {
|
async loadPages(uid, entity: Entity, field, params = {}, pagination = {}) {
|
||||||
if (!_.isString(field)) {
|
if (!_.isString(field)) {
|
||||||
throw new Error(`Invalid load. Expected "${field}" to be a string`);
|
throw new Error(`Invalid load. Expected "${field}" to be a string`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
import { pick } from 'lodash/fp';
|
import { pick } from 'lodash/fp';
|
||||||
|
|
||||||
const pickSelectionParams = pick(['fields', 'populate']);
|
import type { Common } from '../../types';
|
||||||
|
import type { Params } from './types';
|
||||||
|
|
||||||
|
const pickSelectionParams = <T extends Params.Pick<Common.UID.ContentType, 'fields' | 'populate'>>(
|
||||||
|
data: T
|
||||||
|
): Pick<T, 'fields' | 'populate'> => pick(['fields', 'populate'])(data);
|
||||||
|
|
||||||
export { pickSelectionParams };
|
export { pickSelectionParams };
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import type { Attribute, Common, Utils } from '../../../types';
|
import type { Attribute, Common, Utils } from '../../../types';
|
||||||
import type { PartialEntity, Entity, Result, PaginatedResult } from './result';
|
import type { PartialEntity, Entity, Result, PaginatedResult } from './result';
|
||||||
|
import type { UploadFile } from '../../utils/upload-files';
|
||||||
|
|
||||||
import type * as Params from './params';
|
import type * as Params from './params';
|
||||||
|
|
||||||
@ -12,8 +13,10 @@ export * from './plugin';
|
|||||||
type WrapAction = Omit<keyof EntityService, 'wrapParams' | 'wrapResult' | 'emitEvent'>;
|
type WrapAction = Omit<keyof EntityService, 'wrapParams' | 'wrapResult' | 'emitEvent'>;
|
||||||
|
|
||||||
export interface EntityService {
|
export interface EntityService {
|
||||||
|
uploadFiles: UploadFile;
|
||||||
|
|
||||||
wrapParams<
|
wrapParams<
|
||||||
TResult = unknown,
|
TResult extends object = object,
|
||||||
TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType,
|
TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType,
|
||||||
TParams extends object = object
|
TParams extends object = object
|
||||||
>(
|
>(
|
||||||
@ -22,7 +25,7 @@ export interface EntityService {
|
|||||||
): Promise<TResult> | TResult;
|
): Promise<TResult> | TResult;
|
||||||
|
|
||||||
wrapResult<
|
wrapResult<
|
||||||
TResult = unknown,
|
TResult = any,
|
||||||
TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType
|
TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType
|
||||||
>(
|
>(
|
||||||
result: unknown,
|
result: unknown,
|
||||||
@ -51,12 +54,14 @@ export interface EntityService {
|
|||||||
>(
|
>(
|
||||||
uid: TContentTypeUID,
|
uid: TContentTypeUID,
|
||||||
params?: TParams
|
params?: TParams
|
||||||
): Utils.Expression.MatchFirst<
|
): Promise<
|
||||||
|
Utils.Expression.MatchFirst<
|
||||||
[
|
[
|
||||||
[Common.UID.IsCollectionType<TContentTypeUID>, Promise<Result<TContentTypeUID, TParams>[]>],
|
[Common.UID.IsCollectionType<TContentTypeUID>, Result<TContentTypeUID, TParams>[]],
|
||||||
[Common.UID.IsSingleType<TContentTypeUID>, Promise<Result<TContentTypeUID, TParams> | null>]
|
[Common.UID.IsSingleType<TContentTypeUID>, Result<TContentTypeUID, TParams> | null]
|
||||||
],
|
],
|
||||||
Promise<(Result<TContentTypeUID, TParams> | null) | Result<TContentTypeUID, TParams>[]>
|
(Result<TContentTypeUID, TParams> | null) | Result<TContentTypeUID, TParams>[]
|
||||||
|
>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
findOne<
|
findOne<
|
||||||
@ -134,7 +139,7 @@ export interface EntityService {
|
|||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
findWithRelationCounts<
|
findWithRelationCounts<
|
||||||
TContentTypeUID extends Common.UID.Schema,
|
TContentTypeUID extends Common.UID.ContentType,
|
||||||
TParams extends Params.Pick<
|
TParams extends Params.Pick<
|
||||||
TContentTypeUID,
|
TContentTypeUID,
|
||||||
| 'fields'
|
| 'fields'
|
||||||
@ -155,7 +160,7 @@ export interface EntityService {
|
|||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
findWithRelationCountsPage<
|
findWithRelationCountsPage<
|
||||||
TContentTypeUID extends Common.UID.Schema,
|
TContentTypeUID extends Common.UID.ContentType,
|
||||||
TParams extends Params.Pick<
|
TParams extends Params.Pick<
|
||||||
TContentTypeUID,
|
TContentTypeUID,
|
||||||
| 'fields'
|
| 'fields'
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export type ScalarValues = GetValue<
|
|||||||
| Attribute.Text
|
| Attribute.Text
|
||||||
| Attribute.Time
|
| Attribute.Time
|
||||||
| Attribute.Timestamp
|
| Attribute.Timestamp
|
||||||
| Attribute.UID<Common.UID.Schema | undefined>
|
| Attribute.UID<Common.UID.Schema>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export type IsEnabled<TSchemaUID extends Common.UID.Schema> = Utils.Expression.M
|
|||||||
[
|
[
|
||||||
[
|
[
|
||||||
Common.UID.IsContentType<TSchemaUID>,
|
Common.UID.IsContentType<TSchemaUID>,
|
||||||
Utils.Expression.IsTrue<Common.Schemas[TSchemaUID]['options']['draftAndPublish']>
|
Utils.Expression.IsTrue<NonNullable<Common.Schemas[TSchemaUID]['options']>['draftAndPublish']>
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
// Here, we're manually excluding potential overlap between Component and ContentTypes' UIDs and thus preventing false positives
|
// Here, we're manually excluding potential overlap between Component and ContentTypes' UIDs and thus preventing false positives
|
||||||
@ -33,6 +33,7 @@ export type For<TSchemaUID extends Common.UID.Schema> = IsEnabled<TSchemaUID> ex
|
|||||||
// Then add the publicationState param
|
// Then add the publicationState param
|
||||||
{ publicationState?: Kind },
|
{ publicationState?: Kind },
|
||||||
// Else, don't do anything
|
// Else, don't do anything
|
||||||
{}
|
unknown
|
||||||
>
|
>
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
|
|||||||
@ -60,11 +60,14 @@ export type PaginatedResult<
|
|||||||
*/
|
*/
|
||||||
export type GetValues<
|
export type GetValues<
|
||||||
TSchemaUID extends Common.UID.Schema,
|
TSchemaUID extends Common.UID.Schema,
|
||||||
TFields extends Attribute.GetKeys<TSchemaUID>,
|
TFields extends Attribute.GetKeys<TSchemaUID> = Attribute.GetNonPopulatableKeys<TSchemaUID>,
|
||||||
TPopulate extends Attribute.GetKeys<TSchemaUID>
|
TPopulate extends Attribute.GetKeys<TSchemaUID> = Attribute.GetPopulatableKeys<TSchemaUID>
|
||||||
> = Utils.Expression.If<
|
> = Utils.Expression.If<
|
||||||
Common.AreSchemaRegistriesExtended,
|
Common.AreSchemaRegistriesExtended,
|
||||||
Utils.Guard.Never<TFields | TPopulate, Attribute.GetKeys<TSchemaUID>> extends infer TKeys
|
Utils.Guard.Never<
|
||||||
|
TFields | TPopulate,
|
||||||
|
Attribute.GetKeys<TSchemaUID>
|
||||||
|
> extends infer TKeys extends Attribute.GetKeys<TSchemaUID>
|
||||||
? Attribute.GetValues<TSchemaUID, TKeys>
|
? Attribute.GetValues<TSchemaUID, TKeys>
|
||||||
: never,
|
: never,
|
||||||
AnyEntity
|
AnyEntity
|
||||||
@ -72,14 +75,17 @@ export type GetValues<
|
|||||||
|
|
||||||
type ExtractFields<
|
type ExtractFields<
|
||||||
TSchemaUID extends Common.UID.Schema,
|
TSchemaUID extends Common.UID.Schema,
|
||||||
TFields extends Params.Fields.Any<TSchemaUID>
|
TFields extends Params.Fields.Any<TSchemaUID> | undefined
|
||||||
> = Utils.Expression.MatchFirst<
|
> = Utils.Expression.MatchFirst<
|
||||||
[
|
[
|
||||||
// No fields provided
|
// No fields provided
|
||||||
[
|
[
|
||||||
Utils.Expression.Or<
|
Utils.Expression.Or<
|
||||||
Utils.Expression.StrictEqual<TFields, Params.Fields.Any<TSchemaUID>>,
|
Utils.Expression.StrictEqual<TFields, Params.Fields.Any<TSchemaUID>>,
|
||||||
Utils.Expression.IsNever<TFields>
|
Utils.Expression.Or<
|
||||||
|
Utils.Expression.IsNever<TFields>,
|
||||||
|
Utils.Expression.StrictEqual<TFields, undefined>
|
||||||
|
>
|
||||||
>,
|
>,
|
||||||
never
|
never
|
||||||
],
|
],
|
||||||
@ -121,7 +127,7 @@ type ParseStringFields<
|
|||||||
|
|
||||||
type ExtractPopulate<
|
type ExtractPopulate<
|
||||||
TSchemaUID extends Common.UID.Schema,
|
TSchemaUID extends Common.UID.Schema,
|
||||||
TPopulate extends Params.Populate.Any<TSchemaUID>
|
TPopulate extends Params.Populate.Any<TSchemaUID> | undefined
|
||||||
> = Utils.Expression.MatchFirst<
|
> = Utils.Expression.MatchFirst<
|
||||||
[
|
[
|
||||||
// No populate provided
|
// No populate provided
|
||||||
@ -166,7 +172,7 @@ type ExtractPopulate<
|
|||||||
type ParsePopulateDotNotation<
|
type ParsePopulateDotNotation<
|
||||||
TSchemaUID extends Common.UID.Schema,
|
TSchemaUID extends Common.UID.Schema,
|
||||||
TPopulate extends Params.Populate.StringNotation<TSchemaUID>
|
TPopulate extends Params.Populate.StringNotation<TSchemaUID>
|
||||||
> = Utils.String.Split<Utils.Cast<TPopulate, string>, '.'>[0];
|
> = Utils.Cast<Utils.String.Split<Utils.Cast<TPopulate, string>, '.'>[0], Attribute.GetPopulatableKeys<TSchemaUID>>;
|
||||||
|
|
||||||
type ParseStringPopulate<
|
type ParseStringPopulate<
|
||||||
TSchemaUID extends Common.UID.Schema,
|
TSchemaUID extends Common.UID.Schema,
|
||||||
|
|||||||
@ -1,14 +1,16 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { Attribute, Common, Schema } from '../../types';
|
import type { Attribute, Common, Schema } from '../../types';
|
||||||
|
|
||||||
|
export type UploadFile = (
|
||||||
|
uid: Common.UID.Schema,
|
||||||
|
entity: Record<string, unknown>,
|
||||||
|
files: Record<string, unknown>
|
||||||
|
) => Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload files and link them to an entity
|
* Upload files and link them to an entity
|
||||||
*/
|
*/
|
||||||
export default async (
|
const uploadFile: UploadFile = async (uid, entity, files) => {
|
||||||
uid: Common.UID.ContentType | Common.UID.Component,
|
|
||||||
entity: Record<string, unknown>,
|
|
||||||
files: { [key: string]: unknown }
|
|
||||||
) => {
|
|
||||||
const modelDef = strapi.getModel(uid);
|
const modelDef = strapi.getModel(uid);
|
||||||
|
|
||||||
if (!_.has(strapi.plugins, 'upload')) {
|
if (!_.has(strapi.plugins, 'upload')) {
|
||||||
@ -85,3 +87,5 @@ export default async (
|
|||||||
|
|
||||||
await Promise.all(Object.keys(files).map((key) => doUpload(key, files[key])));
|
await Promise.all(Object.keys(files).map((key) => doUpload(key, files[key])));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default uploadFile;
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
// Exports from core should already be modules
|
// Exports from core should already be modules
|
||||||
export * from './core';
|
export * from './core';
|
||||||
|
|
||||||
export * as EntityService from '../services/entity-service';
|
|
||||||
|
|
||||||
export * as CoreApi from './core-api';
|
export * as CoreApi from './core-api';
|
||||||
export * as Utils from './utils';
|
export * as Utils from './utils';
|
||||||
export * as Shared from './shared';
|
export * as Shared from './shared';
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Common, Schema, UID } from '..';
|
import type { Common, Schema, UID } from '..';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared service registry
|
* Shared service registry
|
||||||
@ -35,17 +35,6 @@ export interface Middlewares {
|
|||||||
*/
|
*/
|
||||||
export interface ContentTypes {
|
export interface ContentTypes {
|
||||||
[key: UID.ContentType]: Schema.ContentType;
|
[key: UID.ContentType]: Schema.ContentType;
|
||||||
// 'admin::coucou': {
|
|
||||||
// modelType: 'contentType';
|
|
||||||
// kind: 'collectionType';
|
|
||||||
// uid: 'admin::coucou';
|
|
||||||
// attributes: Schema.CollectionType['attributes'];
|
|
||||||
// info: {
|
|
||||||
// displayName: 'coucou';
|
|
||||||
// singularName: 'coucou';
|
|
||||||
// pluralName: 'coucous';
|
|
||||||
// };
|
|
||||||
// };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -62,8 +62,8 @@ export interface Params {
|
|||||||
fields?: FieldsParams;
|
fields?: FieldsParams;
|
||||||
filters?: FiltersParams;
|
filters?: FiltersParams;
|
||||||
populate?: PopulateParams;
|
populate?: PopulateParams;
|
||||||
count: boolean;
|
count?: boolean;
|
||||||
ordering: unknown;
|
ordering?: unknown;
|
||||||
_q?: string;
|
_q?: string;
|
||||||
limit?: number | string;
|
limit?: number | string;
|
||||||
start?: number | string;
|
start?: number | string;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user