mirror of
https://github.com/strapi/strapi.git
synced 2025-11-03 19:36:20 +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 type { Schema } from '../../../types';
|
||||
import type { Common, Schema } from '../../../types';
|
||||
import { Data } from '../types/params';
|
||||
|
||||
const applyTransforms = (
|
||||
data: Record<string, unknown>,
|
||||
@ -9,9 +10,9 @@ const applyTransforms = (
|
||||
) => {
|
||||
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];
|
||||
|
||||
if (!attribute) {
|
||||
|
||||
@ -4,10 +4,10 @@ import bcrypt from 'bcryptjs';
|
||||
import type { Attribute } from '../../../types';
|
||||
|
||||
type Transforms = {
|
||||
[key in Attribute.Kind]?: (
|
||||
value: Attribute.GetValue<Attribute.Attribute<key>>,
|
||||
context: { attribute: Attribute.Attribute<key>; attributeName: string }
|
||||
) => unknown;
|
||||
[TKind in Attribute.Kind]?: (
|
||||
value: Attribute.GetValue<Attribute.Attribute<TKind>>,
|
||||
context: { attribute: Attribute.Attribute<TKind>; attributeName: string }
|
||||
) => Attribute.GetValue<Attribute.Attribute<TKind>>;
|
||||
};
|
||||
|
||||
const transforms: Transforms = {
|
||||
@ -22,6 +22,6 @@ const transforms: Transforms = {
|
||||
|
||||
return bcrypt.hashSync(value, rounds);
|
||||
},
|
||||
} as const;
|
||||
};
|
||||
|
||||
export default transforms;
|
||||
|
||||
@ -38,8 +38,6 @@ type Context = {
|
||||
contentType: Schema.ContentType;
|
||||
};
|
||||
|
||||
type Entity = {};
|
||||
|
||||
const transformLoadParamsToQuery = (
|
||||
uid: string,
|
||||
field: string,
|
||||
@ -89,19 +87,22 @@ const createDefaultImplementation = ({
|
||||
eventHub: EventHub;
|
||||
entityValidator: EntityValidator;
|
||||
}): types.EntityService => ({
|
||||
/**
|
||||
* Upload files utility
|
||||
*/
|
||||
uploadFiles,
|
||||
|
||||
async wrapParams(options) {
|
||||
async wrapParams(options: any) {
|
||||
return options;
|
||||
},
|
||||
|
||||
async wrapResult(result) {
|
||||
async wrapResult(result: any) {
|
||||
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
|
||||
if (uid === 'admin::audit-log') {
|
||||
if (uid === ('admin::audit-log' as Common.UID.ContentType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -115,7 +116,7 @@ const createDefaultImplementation = ({
|
||||
});
|
||||
},
|
||||
|
||||
async findMany(uid: Common.UID.Schema, opts) {
|
||||
async findMany(uid, opts) {
|
||||
const { kind } = strapi.getModel(uid);
|
||||
|
||||
const wrappedParams = await this.wrapParams(opts, { uid, action: 'findMany' });
|
||||
@ -131,7 +132,7 @@ const createDefaultImplementation = ({
|
||||
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 query = transformParamsToQuery(uid, wrappedParams);
|
||||
@ -183,16 +184,24 @@ const createDefaultImplementation = ({
|
||||
},
|
||||
|
||||
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;
|
||||
|
||||
if (!data) {
|
||||
throw new Error('cannot create');
|
||||
}
|
||||
|
||||
const model = strapi.getModel(uid);
|
||||
|
||||
const isDraft = contentTypesUtils.isDraft(data, model);
|
||||
const validData = await entityValidator.validateEntityCreation(model, data, { isDraft });
|
||||
|
||||
// select / populate
|
||||
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
||||
const x = pickSelectionParams(wrappedParams);
|
||||
|
||||
const query = transformParamsToQuery(uid, x);
|
||||
|
||||
// TODO: wrap into transaction
|
||||
const componentData = await createComponents(uid, validData);
|
||||
@ -353,7 +362,7 @@ const createDefaultImplementation = ({
|
||||
return entity;
|
||||
},
|
||||
// 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' });
|
||||
|
||||
// select / populate
|
||||
@ -383,7 +392,7 @@ const createDefaultImplementation = ({
|
||||
return deletedEntities;
|
||||
},
|
||||
|
||||
async load(uid: Common.UID.Schema, entity, field, params = {}) {
|
||||
async load(uid, entity, field, params = {}) {
|
||||
if (!_.isString(field)) {
|
||||
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' });
|
||||
},
|
||||
|
||||
async loadPages(uid: Common.UID.Schema, entity: Entity, field, params = {}, pagination = {}) {
|
||||
async loadPages(uid, entity: Entity, field, params = {}, pagination = {}) {
|
||||
if (!_.isString(field)) {
|
||||
throw new Error(`Invalid load. Expected "${field}" to be a string`);
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
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 };
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type { Attribute, Common, Utils } from '../../../types';
|
||||
import type { PartialEntity, Entity, Result, PaginatedResult } from './result';
|
||||
import type { UploadFile } from '../../utils/upload-files';
|
||||
|
||||
import type * as Params from './params';
|
||||
|
||||
@ -12,8 +13,10 @@ export * from './plugin';
|
||||
type WrapAction = Omit<keyof EntityService, 'wrapParams' | 'wrapResult' | 'emitEvent'>;
|
||||
|
||||
export interface EntityService {
|
||||
uploadFiles: UploadFile;
|
||||
|
||||
wrapParams<
|
||||
TResult = unknown,
|
||||
TResult extends object = object,
|
||||
TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType,
|
||||
TParams extends object = object
|
||||
>(
|
||||
@ -22,7 +25,7 @@ export interface EntityService {
|
||||
): Promise<TResult> | TResult;
|
||||
|
||||
wrapResult<
|
||||
TResult = unknown,
|
||||
TResult = any,
|
||||
TContentTypeUID extends Common.UID.ContentType = Common.UID.ContentType
|
||||
>(
|
||||
result: unknown,
|
||||
@ -51,12 +54,14 @@ export interface EntityService {
|
||||
>(
|
||||
uid: TContentTypeUID,
|
||||
params?: TParams
|
||||
): Utils.Expression.MatchFirst<
|
||||
[
|
||||
[Common.UID.IsCollectionType<TContentTypeUID>, Promise<Result<TContentTypeUID, TParams>[]>],
|
||||
[Common.UID.IsSingleType<TContentTypeUID>, Promise<Result<TContentTypeUID, TParams> | null>]
|
||||
],
|
||||
Promise<(Result<TContentTypeUID, TParams> | null) | Result<TContentTypeUID, TParams>[]>
|
||||
): Promise<
|
||||
Utils.Expression.MatchFirst<
|
||||
[
|
||||
[Common.UID.IsCollectionType<TContentTypeUID>, Result<TContentTypeUID, TParams>[]],
|
||||
[Common.UID.IsSingleType<TContentTypeUID>, Result<TContentTypeUID, TParams> | null]
|
||||
],
|
||||
(Result<TContentTypeUID, TParams> | null) | Result<TContentTypeUID, TParams>[]
|
||||
>
|
||||
>;
|
||||
|
||||
findOne<
|
||||
@ -134,7 +139,7 @@ export interface EntityService {
|
||||
* @deprecated
|
||||
*/
|
||||
findWithRelationCounts<
|
||||
TContentTypeUID extends Common.UID.Schema,
|
||||
TContentTypeUID extends Common.UID.ContentType,
|
||||
TParams extends Params.Pick<
|
||||
TContentTypeUID,
|
||||
| 'fields'
|
||||
@ -155,7 +160,7 @@ export interface EntityService {
|
||||
* @deprecated
|
||||
*/
|
||||
findWithRelationCountsPage<
|
||||
TContentTypeUID extends Common.UID.Schema,
|
||||
TContentTypeUID extends Common.UID.ContentType,
|
||||
TParams extends Params.Pick<
|
||||
TContentTypeUID,
|
||||
| 'fields'
|
||||
|
||||
@ -55,7 +55,7 @@ export type ScalarValues = GetValue<
|
||||
| Attribute.Text
|
||||
| Attribute.Time
|
||||
| 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>,
|
||||
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
|
||||
@ -33,6 +33,7 @@ export type For<TSchemaUID extends Common.UID.Schema> = IsEnabled<TSchemaUID> ex
|
||||
// Then add the publicationState param
|
||||
{ publicationState?: Kind },
|
||||
// Else, don't do anything
|
||||
{}
|
||||
unknown
|
||||
>
|
||||
: never;
|
||||
|
||||
|
||||
@ -60,11 +60,14 @@ export type PaginatedResult<
|
||||
*/
|
||||
export type GetValues<
|
||||
TSchemaUID extends Common.UID.Schema,
|
||||
TFields extends Attribute.GetKeys<TSchemaUID>,
|
||||
TPopulate extends Attribute.GetKeys<TSchemaUID>
|
||||
TFields extends Attribute.GetKeys<TSchemaUID> = Attribute.GetNonPopulatableKeys<TSchemaUID>,
|
||||
TPopulate extends Attribute.GetKeys<TSchemaUID> = Attribute.GetPopulatableKeys<TSchemaUID>
|
||||
> = Utils.Expression.If<
|
||||
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>
|
||||
: never,
|
||||
AnyEntity
|
||||
@ -72,14 +75,17 @@ export type GetValues<
|
||||
|
||||
type ExtractFields<
|
||||
TSchemaUID extends Common.UID.Schema,
|
||||
TFields extends Params.Fields.Any<TSchemaUID>
|
||||
TFields extends Params.Fields.Any<TSchemaUID> | undefined
|
||||
> = Utils.Expression.MatchFirst<
|
||||
[
|
||||
// No fields provided
|
||||
[
|
||||
Utils.Expression.Or<
|
||||
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
|
||||
],
|
||||
@ -121,7 +127,7 @@ type ParseStringFields<
|
||||
|
||||
type ExtractPopulate<
|
||||
TSchemaUID extends Common.UID.Schema,
|
||||
TPopulate extends Params.Populate.Any<TSchemaUID>
|
||||
TPopulate extends Params.Populate.Any<TSchemaUID> | undefined
|
||||
> = Utils.Expression.MatchFirst<
|
||||
[
|
||||
// No populate provided
|
||||
@ -166,7 +172,7 @@ type ExtractPopulate<
|
||||
type ParsePopulateDotNotation<
|
||||
TSchemaUID extends Common.UID.Schema,
|
||||
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<
|
||||
TSchemaUID extends Common.UID.Schema,
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
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
|
||||
*/
|
||||
export default async (
|
||||
uid: Common.UID.ContentType | Common.UID.Component,
|
||||
entity: Record<string, unknown>,
|
||||
files: { [key: string]: unknown }
|
||||
) => {
|
||||
const uploadFile: UploadFile = async (uid, entity, files) => {
|
||||
const modelDef = strapi.getModel(uid);
|
||||
|
||||
if (!_.has(strapi.plugins, 'upload')) {
|
||||
@ -85,3 +87,5 @@ export default async (
|
||||
|
||||
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
|
||||
export * from './core';
|
||||
|
||||
export * as EntityService from '../services/entity-service';
|
||||
|
||||
export * as CoreApi from './core-api';
|
||||
export * as Utils from './utils';
|
||||
export * as Shared from './shared';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Common, Schema, UID } from '..';
|
||||
import type { Common, Schema, UID } from '..';
|
||||
|
||||
/**
|
||||
* Shared service registry
|
||||
@ -35,17 +35,6 @@ export interface Middlewares {
|
||||
*/
|
||||
export interface ContentTypes {
|
||||
[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;
|
||||
filters?: FiltersParams;
|
||||
populate?: PopulateParams;
|
||||
count: boolean;
|
||||
ordering: unknown;
|
||||
count?: boolean;
|
||||
ordering?: unknown;
|
||||
_q?: string;
|
||||
limit?: number | string;
|
||||
start?: number | string;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user