chore: improve middleware api

This commit is contained in:
Alexandre Bodin 2024-04-04 22:37:55 +02:00
parent 57ef329165
commit 5e5bcf8c8f
6 changed files with 76 additions and 66 deletions

View File

@ -137,9 +137,13 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
return next();
}
// Ignore actions that don't mutate documents
// NOTE: can do type narrowing with array includes
if (
!['create', 'update', 'publish', 'unpublish', 'discardDraft'].includes(context.action)
context.action !== 'create' &&
context.action !== 'update' &&
context.action !== 'publish' &&
context.action !== 'unpublish' &&
context.action !== 'discardDraft'
) {
return next();
}
@ -154,9 +158,8 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
const documentContext =
context.action === 'create'
? // @ts-expect-error The context args are not typed correctly
{ documentId: result.documentId, locale: context.args[0]?.locale }
: { documentId: context.args[0], locale: context.args[1]?.locale };
? { documentId: result.documentId, locale: context.params?.locale }
: { documentId: context.params.documentId, locale: context.params?.locale };
const locale = documentContext.locale ?? (await localesService.getDefaultLocale());
const document = await strapi.documents(contentTypeUid).findOne({

View File

@ -1,8 +1,8 @@
import type { UID, Modules } from '@strapi/types';
export type RepositoryFactoryMethod = <TCollectionTypeUID extends UID.CollectionType>(
uid: TCollectionTypeUID
) => Modules.Documents.ServiceInstance<TCollectionTypeUID>;
export type RepositoryFactoryMethod = <TContentTypeUID extends UID.ContentType>(
uid: TContentTypeUID
) => Modules.Documents.ServiceInstance<TContentTypeUID>;
export const wrapInTransaction = (fn: (...args: any) => any) => {
return (...args: any[]) => strapi.db.transaction?.(() => fn(...args));

View File

@ -1,4 +1,4 @@
import type { Core, Modules } from '@strapi/types';
import type { Core, Modules, UID } from '@strapi/types';
import { createMiddlewareManager, databaseErrorsMiddleware } from './middlewares';
import { createContentTypeRepository } from './repository';
@ -24,7 +24,7 @@ export const createDocumentService = (strapi: Core.Strapi): Modules.Documents.Se
middlewares.use(databaseErrorsMiddleware);
const factory = function factory(uid) {
const factory = function factory(uid: UID.ContentType) {
if (repositories.has(uid)) {
return repositories.get(uid)!;
}
@ -32,7 +32,7 @@ export const createDocumentService = (strapi: Core.Strapi): Modules.Documents.Se
const contentType = strapi.contentType(uid);
const repository = createContentTypeRepository(uid);
repositories.set(uid, middlewares.wrapObject(repository, { contentType }));
repositories.set(uid, middlewares.wrapObject(repository, { uid, contentType }));
return repository;
} as Modules.Documents.Service;

View File

@ -24,7 +24,7 @@ export const createMiddlewareManager = () => {
return next();
},
wrapObject<TSource extends Record<string, any>>(source: TSource, ctxDefaults = {}): TSource {
wrapObject<TSource>(source: TSource, ctxDefaults = {}): TSource {
const facade: TSource = {} as TSource;
for (const key in source) {

View File

@ -1,19 +1,19 @@
// Utility type to reuse Param definition in MiddlewareContext
import type { Schema } from '../..';
import type { ServiceInstance } from './service-instance';
import type { Schema, UID } from '../..';
import type { ServiceInstance, ServiceParams } from './service-instance';
export interface Context<
TAction extends keyof ServiceInstance = keyof ServiceInstance,
TArgs = Parameters<ServiceInstance[TAction]>,
> {
contentType: Schema.ContentType;
action: TAction;
args: TArgs;
}
export type Context<TUID extends UID.ContentType = UID.ContentType> = {
[TUIDKey in TUID]: {
[TKey in keyof ServiceParams<TUIDKey>]: {
contentType: Schema.ContentType<TUIDKey>;
uid: TUIDKey;
action: TKey;
params: ServiceParams<TUIDKey>[TKey];
};
}[keyof ServiceParams<TUIDKey>];
}[TUID];
export type Middleware = (
ctx: Context,
next: () => Promise<ReturnType<ServiceInstance[keyof ServiceInstance]>>
) =>
| ReturnType<ServiceInstance[keyof ServiceInstance]>
| Promise<ReturnType<ServiceInstance[keyof ServiceInstance]>>;
next: () => ReturnType<ServiceInstance[keyof ServiceInstance]>
) => ReturnType<ServiceInstance[keyof ServiceInstance]>;

View File

@ -8,6 +8,34 @@ import type { IsDraftAndPublishEnabled } from './draft-and-publish';
import type * as Params from './params/document-engine';
import type * as Result from './result/document-engine';
export type ServiceParams<TContentTypeUID extends UID.ContentType = UID.ContentType> = {
findMany: Params.FindMany<TContentTypeUID>;
findFirst: Params.FindFirst<TContentTypeUID>;
findOne: Params.FindOne<TContentTypeUID>;
delete: Params.Delete<TContentTypeUID>;
create: Params.Create<TContentTypeUID>;
clone: Params.Clone<TContentTypeUID>;
update: Params.Update<TContentTypeUID>;
count: Params.Count<TContentTypeUID>;
publish: Params.Publish<TContentTypeUID>;
unpublish: Params.Unpublish<TContentTypeUID>;
discardDraft: Params.DiscardDraft<TContentTypeUID>;
};
export type ServiceResults<TContentTypeUID extends UID.ContentType = UID.ContentType> = {
findMany: Result.FindMany<TContentTypeUID, Params.FindMany<TContentTypeUID>>;
findFirst: Result.FindFirst<TContentTypeUID, Params.FindFirst<TContentTypeUID>>;
findOne: Result.FindOne<TContentTypeUID, Params.FindOne<TContentTypeUID>>;
delete: Result.Delete;
create: Result.Create<TContentTypeUID, Params.Create<TContentTypeUID>>;
clone: Result.Clone<TContentTypeUID, Params.Clone<TContentTypeUID>>;
update: Result.Update<TContentTypeUID, Params.Update<TContentTypeUID>>;
count: Result.Count;
publish: Result.Publish<TContentTypeUID, Params.Publish<TContentTypeUID>>;
unpublish: Result.Unpublish<TContentTypeUID, Params.Unpublish<TContentTypeUID>>;
discardDraft: Result.DiscardDraft<TContentTypeUID, Params.DiscardDraft<TContentTypeUID>>;
};
// TODO: move to common place
type ComponentBody = {
[key: string]: AttributeUtils.GetValue<
@ -17,65 +45,44 @@ type ComponentBody = {
>;
};
export type ServiceInstance<TContentTypeUID extends UID.ContentType = UID.ContentType> = {
findMany: <TParams extends Params.FindMany<TContentTypeUID>>(
params?: TParams
) => Result.FindMany<TContentTypeUID, TParams>;
findFirst: <TParams extends Params.FindFirst<TContentTypeUID>>(
params?: TParams
) => Result.FindFirst<TContentTypeUID, TParams>;
findOne: <TParams extends Params.FindOne<TContentTypeUID>>(
params: TParams
) => Result.FindOne<TContentTypeUID, TParams>;
delete: <TParams extends Params.Delete<TContentTypeUID>>(params: TParams) => Result.Delete;
create: <TParams extends Params.Create<TContentTypeUID>>(
params: TParams
) => Result.Create<TContentTypeUID, TParams>;
export type ServiceInstance<
TContentTypeUID extends UID.ContentType = UID.ContentType,
TServiceParams extends ServiceParams<TContentTypeUID> = ServiceParams<TContentTypeUID>,
TServiceResults extends ServiceResults<TContentTypeUID> = ServiceResults<TContentTypeUID>,
> = {
findMany: (params?: TServiceParams['findMany']) => TServiceResults['findMany'];
findFirst: (params?: TServiceParams['findFirst']) => TServiceResults['findFirst'];
findOne: (params: TServiceParams['findOne']) => TServiceResults['findOne'];
delete: (params: TServiceParams['delete']) => TServiceResults['delete'];
create: (params: TServiceParams['create']) => TServiceResults['create'];
/**
* @internal
* Exposed for use within the Strapi Admin Panel
*/
clone: <TParams extends Params.Clone<TContentTypeUID>>(
params: TParams
) => Result.Clone<TContentTypeUID, TParams>;
update: <TParams extends Params.Update<TContentTypeUID>>(
params: TParams
) => Result.Update<TContentTypeUID, TParams>;
count: <TParams extends Params.Count<TContentTypeUID>>(params?: TParams) => Result.Count;
clone: (params: TServiceParams['clone']) => TServiceResults['clone'];
update: (params: TServiceParams['update']) => TServiceResults['update'];
count: (params?: TServiceParams['count']) => TServiceResults['count'];
// Publication methods are only enabled if D&P is enabled for the content type
publish: Utils.If<
// If draft and publish is enabled for the content type
IsDraftAndPublishEnabled<TContentTypeUID>,
// Then, publish method is enabled
<TParams extends Params.Publish<TContentTypeUID>>(
params: TParams
) => Result.Publish<TContentTypeUID, TParams>,
(params: TServiceParams['publish']) => TServiceResults['publish'],
// Otherwise, disable it
undefined
never
>;
unpublish: Utils.If<
IsDraftAndPublishEnabled<TContentTypeUID>,
<TParams extends Params.Unpublish<TContentTypeUID>>(
params: TParams
) => Result.Unpublish<TContentTypeUID, TParams>,
undefined
(params: TServiceParams['unpublish']) => TServiceResults['unpublish'],
never
>;
discardDraft: Utils.If<
IsDraftAndPublishEnabled<TContentTypeUID>,
<TParams extends Params.DiscardDraft<TContentTypeUID>>(
params: TParams
) => Result.DiscardDraft<TContentTypeUID, TParams>,
undefined
(params: TServiceParams['discardDraft']) => TServiceResults['discardDraft'],
never
>;
/**