mirror of
https://github.com/strapi/strapi.git
synced 2025-11-02 10:55:37 +00:00
Fix Document Service Typing Issues (#21110)
This commit is contained in:
parent
79313050d9
commit
1204e14d29
@ -1,33 +1,89 @@
|
||||
import type { UID, Schema } from '../..';
|
||||
import type * as EntityService from '../entity-service';
|
||||
import type { UID, Schema, Utils } from '../..';
|
||||
import type { Input, PartialInput } from './params/data';
|
||||
import type * as AttributeUtils from './params/attributes';
|
||||
|
||||
// TODO: move to common place
|
||||
type ComponentBody = {
|
||||
[key: string]: AttributeUtils.GetValue<
|
||||
| Schema.Attribute.Component<UID.Component, false>
|
||||
| Schema.Attribute.Component<UID.Component, true>
|
||||
| Schema.Attribute.DynamicZone
|
||||
>;
|
||||
};
|
||||
/**
|
||||
* Defines the structure of component bodies based on the given schema UID and component-like keys.
|
||||
*
|
||||
* It adapts based on whether schema registries have been extended, either mapping attribute names to
|
||||
* their respective values or using a generic key-value structure if the registries have not been extended.
|
||||
*
|
||||
* @template TSchemaUID - The schema's UID, extending from {@link UID.Schema}, which determines the attribute names and types to use.
|
||||
* @template TComponentLikeKeys - A string type representing the keys to keep that are component-like, defaults to a generic string.
|
||||
*
|
||||
* @example
|
||||
* Using `ComponentBody` in a situation where the schema registries have been extended:
|
||||
* ```typescript
|
||||
* type MyComponentSchemaUID = 'default.mycomponent';
|
||||
* type MyComponentBody = ComponentBody<MyComponentSchemaUID, 'header' | 'footer'>;
|
||||
*
|
||||
* // This resolves to:
|
||||
* // {
|
||||
* // header: AttributeUtils.GetValue<Schema.AttributeByName<MyComponentSchemaUID, 'header'>>;
|
||||
* // footer: AttributeUtils.GetValue<Schema.AttributeByName<MyComponentSchemaUID, 'footer'>>;
|
||||
* // }
|
||||
* ```
|
||||
*
|
||||
* In cases where it's unknown whether schema registries have been extended:
|
||||
* ```typescript
|
||||
* type GenericComponentBody = ComponentBody<UID.Schema>;
|
||||
*
|
||||
* // This resolves to:
|
||||
* // {
|
||||
* // [key: string]: AttributeUtils.GetValue<
|
||||
* // | Schema.Attribute.Component<UID.Component, false>
|
||||
* // | Schema.Attribute.Component<UID.Component, true>
|
||||
* // | Schema.Attribute.DynamicZone
|
||||
* // >;
|
||||
* // }
|
||||
* ```
|
||||
*
|
||||
* @todo: Move to common data structures and make it available for other use
|
||||
*/
|
||||
type ComponentBody<
|
||||
TSchemaUID extends UID.Schema = UID.Schema,
|
||||
TComponentLikeKeys extends string = string,
|
||||
> = Utils.If<
|
||||
Utils.Constants.AreSchemaRegistriesExtended,
|
||||
{
|
||||
[TAttributeName in Extract<
|
||||
Schema.AttributeNamesByType<TSchemaUID, 'component' | 'dynamiczone'>,
|
||||
TComponentLikeKeys
|
||||
>]: AttributeUtils.GetValue<Schema.AttributeByName<TSchemaUID, TAttributeName>>;
|
||||
},
|
||||
{
|
||||
[key: string]: AttributeUtils.GetValue<
|
||||
| Schema.Attribute.Component<UID.Component, false>
|
||||
| Schema.Attribute.Component<UID.Component, true>
|
||||
| Schema.Attribute.DynamicZone
|
||||
>;
|
||||
}
|
||||
>;
|
||||
|
||||
export type ComponentExtension = {
|
||||
/**
|
||||
* Provides methods to manipulate component data in input payloads.
|
||||
*
|
||||
* @template TSchemaUID - Represents a unique identifier for a schema, extending {@link UID.Schema}.
|
||||
*/
|
||||
export type ComponentExtension<TSchemaUID extends UID.Schema> = {
|
||||
/**
|
||||
* Update the component data for a given entity.
|
||||
*
|
||||
* @remark This method is exposed for use within document service middlewares.
|
||||
*
|
||||
* @internal
|
||||
* Exposed for use within document service middlewares
|
||||
*/
|
||||
updateComponents: (
|
||||
entityToUpdate: {
|
||||
id: EntityService.Params.Attribute.ID;
|
||||
},
|
||||
data: EntityService.Params.Data.Input<UID.Schema>
|
||||
) => Promise<ComponentBody>;
|
||||
updateComponents<const TData extends Input<TSchemaUID>>(
|
||||
entityToUpdate: { id: AttributeUtils.ID },
|
||||
data: TData
|
||||
): Promise<ComponentBody<TSchemaUID, Extract<keyof TData, string>>>;
|
||||
|
||||
/**
|
||||
* Omits component-like fields from the given input data.
|
||||
*
|
||||
* @remark This method is exposed for use within document service middlewares.
|
||||
*
|
||||
* @internal
|
||||
* Exposed for use within document service middlewares
|
||||
*/
|
||||
omitComponentData: (
|
||||
data: EntityService.Params.Data.Input<Schema.ContentType['uid']>
|
||||
) => Partial<EntityService.Params.Data.Input<Schema.ContentType['uid']>>;
|
||||
omitComponentData<const TData extends PartialInput<TSchemaUID>>(data: TData): TData;
|
||||
};
|
||||
|
||||
@ -19,8 +19,10 @@ type ServiceUtils = {
|
||||
export type Service = {
|
||||
<TContentTypeUID extends UID.ContentType>(
|
||||
uid: TContentTypeUID
|
||||
): ServiceInstance<TContentTypeUID> & ComponentExtension;
|
||||
): ServiceInstance<TContentTypeUID> & ComponentExtension<TContentTypeUID>;
|
||||
|
||||
utils: ServiceUtils;
|
||||
|
||||
/** Add a middleware for all uid's and a specific action
|
||||
* @example - Add a default locale
|
||||
* strapi.documents.use((ctx, next) => {
|
||||
|
||||
@ -1,5 +1,72 @@
|
||||
import type * as UID from '../../../uid';
|
||||
|
||||
import type * as Utils from '../../../utils';
|
||||
import type * as AttributeUtils from './attributes';
|
||||
|
||||
/**
|
||||
* Represents the input data for a given content-type UID.
|
||||
*
|
||||
* This type evaluates the schema based on the given content-type UID, and extracts the attribute values
|
||||
* accordingly.
|
||||
*
|
||||
* It combines optional and required attributes, while excluding certain relational attributes
|
||||
* that don't target specific schemas like polymorphic relations.
|
||||
*
|
||||
* @template TSchemaUID - A unique identifier for a schema, extending {@link UID.Schema}.
|
||||
*
|
||||
* @remark
|
||||
* The attributes' values are customized to allow additional input formats that are going to be
|
||||
* transformed in the document service methods.
|
||||
*
|
||||
* For example, relational attributes can use the re-ordering API.
|
||||
*
|
||||
* @example
|
||||
* Defining input for a content type schema:
|
||||
*
|
||||
* ```typescript
|
||||
* import type { UID } from '@strapi/types';
|
||||
*
|
||||
* // Assume there's a schema with a UID of 'api::article.article'
|
||||
* type ArticleInput = Input<'api::article.article'>;
|
||||
*
|
||||
* // Example usage of ArticleInput with typed attributes
|
||||
* const articleData: ArticleInput = {
|
||||
* title: 'My Article', // Required title property
|
||||
* content: 'Content of the article', // Required content property
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* Handling component schema with optional and required attributes:
|
||||
*
|
||||
* ```typescript
|
||||
* import type { UID } from '@strapi/types';
|
||||
*
|
||||
* // Assume there's a component with a UID of 'default.comment'
|
||||
* type CommentInput = Input<'default.comment'>;
|
||||
*
|
||||
* const commentData: CommentInput = {
|
||||
* text: 'Great article!', // Required text property
|
||||
* author: 'John Doe', // Optional author property
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export type Input<TSchemaUID extends UID.Schema> = AttributeUtils.GetValues<TSchemaUID>;
|
||||
|
||||
/**
|
||||
* Conditionally applies partial types to schema input data based on the extension status of schema registries.
|
||||
*
|
||||
* This type evaluates whether the schema registries have been extended.
|
||||
*
|
||||
* If so, it returns a partial version of `Input<TSchemaUID>`, otherwise it returns the default `Input` type.
|
||||
*
|
||||
* @template TSchemaUID - Represents a unique identifier for a schema, either content-type or component, extending {@link UID.Schema}.
|
||||
*
|
||||
* @remark
|
||||
* This type is particularly useful for ensuring backward compatibility within input data structures,
|
||||
* enabling flexibility during schema transitions or extensions without breaking existing data contracts.
|
||||
*/
|
||||
export type PartialInput<TSchemaUID extends UID.Schema> = Utils.If<
|
||||
Utils.Constants.AreSchemaRegistriesExtended,
|
||||
Partial<Input<TSchemaUID>>,
|
||||
Input<TSchemaUID>
|
||||
>;
|
||||
|
||||
@ -1,76 +1,145 @@
|
||||
import type { Utils } from '../..';
|
||||
|
||||
import type * as Utils from '../../utils';
|
||||
import type * as UID from '../../uid';
|
||||
|
||||
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 ServiceInstance<TContentTypeUID extends UID.ContentType = UID.ContentType> = {
|
||||
findMany<const TParams extends Params.FindMany<TContentTypeUID>>(
|
||||
params?: TParams
|
||||
): Result.FindMany<TContentTypeUID, TParams>;
|
||||
|
||||
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<TContentTypeUID, Params.Delete<TContentTypeUID>>;
|
||||
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>>;
|
||||
};
|
||||
findFirst<const TParams extends Params.FindFirst<TContentTypeUID>>(
|
||||
params?: TParams
|
||||
): Result.FindFirst<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'];
|
||||
findOne<const TParams extends Params.FindOne<TContentTypeUID>>(
|
||||
params: TParams
|
||||
): Result.FindOne<TContentTypeUID, TParams>;
|
||||
|
||||
delete<const TParams extends Params.Delete<TContentTypeUID>>(
|
||||
params: TParams
|
||||
): Result.Delete<TContentTypeUID, TParams>;
|
||||
|
||||
create<const TParams extends Params.Create<TContentTypeUID>>(
|
||||
params: TParams
|
||||
): Result.Create<TContentTypeUID, TParams>;
|
||||
|
||||
update<const TParams extends Params.Update<TContentTypeUID>>(
|
||||
params: TParams
|
||||
): Result.Update<TContentTypeUID, TParams>;
|
||||
|
||||
count<const TParams extends Params.Count<TContentTypeUID>>(params: TParams): Result.Count;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
clone: (params: TServiceParams['clone']) => TServiceResults['clone'];
|
||||
update: (params: TServiceParams['update']) => TServiceResults['update'];
|
||||
count: (params?: TServiceParams['count']) => TServiceResults['count'];
|
||||
clone<const TParams extends Params.Clone<TContentTypeUID>>(
|
||||
params: TParams
|
||||
): Result.Clone<TContentTypeUID, TParams>;
|
||||
} & Utils.If<
|
||||
// Only add publication methods if draft and publish is enabled on the content-type
|
||||
IsDraftAndPublishEnabled<TContentTypeUID>,
|
||||
DraftAndPublishExtension<TContentTypeUID>,
|
||||
unknown
|
||||
>;
|
||||
|
||||
// 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
|
||||
(params: TServiceParams['publish']) => TServiceResults['publish'],
|
||||
// Otherwise, disable it
|
||||
never
|
||||
>;
|
||||
/**
|
||||
* Provides methods for managing the draft and publish lifecycle of a document.
|
||||
*
|
||||
* This interface handles publishing, unpublishing, and discarding
|
||||
* drafts of documents identified by their unique identifier.
|
||||
*
|
||||
* @template TContentTypeUID - The unique identifier type for the content-type, constrained to {@link UID.ContentType}.
|
||||
*/
|
||||
export interface DraftAndPublishExtension<
|
||||
TContentTypeUID extends UID.ContentType = UID.ContentType,
|
||||
> {
|
||||
/**
|
||||
* Publishes the current draft for the given document ID.
|
||||
*/
|
||||
publish<const TParams extends Params.Publish<TContentTypeUID>>(
|
||||
params: TParams
|
||||
): Result.Publish<TContentTypeUID, TParams>;
|
||||
|
||||
unpublish: Utils.If<
|
||||
IsDraftAndPublishEnabled<TContentTypeUID>,
|
||||
(params: TServiceParams['unpublish']) => TServiceResults['unpublish'],
|
||||
never
|
||||
>;
|
||||
/**
|
||||
* Unpublishes a document for the given document ID.
|
||||
*/
|
||||
unpublish<const TParams extends Params.Unpublish<TContentTypeUID>>(
|
||||
params: TParams
|
||||
): Result.Unpublish<TContentTypeUID, TParams>;
|
||||
|
||||
discardDraft: Utils.If<
|
||||
IsDraftAndPublishEnabled<TContentTypeUID>,
|
||||
(params: TServiceParams['discardDraft']) => TServiceResults['discardDraft'],
|
||||
never
|
||||
>;
|
||||
/**
|
||||
* Discards the draft entry for the given document ID and params.
|
||||
*/
|
||||
discardDraft<const TParams extends Params.DiscardDraft<TContentTypeUID>>(
|
||||
params: TParams
|
||||
): Result.DiscardDraft<TContentTypeUID, TParams>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the parameters for various service operations on content types.
|
||||
*
|
||||
* This type aggregates different sets of parameters required for performing operations such as
|
||||
* finding, creating, updating, deleting, cloning, and publishing content within a content management system.
|
||||
*
|
||||
* Each operation has its own set of parameters defined using different subtypes.
|
||||
*
|
||||
* @template TContentTypeUID - Extends {@link UID.ContentType}, used to specify the unique identifier for a content-type.
|
||||
*
|
||||
* @example
|
||||
* Example of how to specify parameters for different operations on a content-type:
|
||||
*
|
||||
* ```typescript
|
||||
* import type { UID } from '../../uid';
|
||||
*
|
||||
* type ArticleServiceParams = ServiceParams<'api::article.article'>;
|
||||
*
|
||||
* // Example: Parameters for finding multiple articles
|
||||
* const findManyParams: ArticleServiceParams['findMany'] = {
|
||||
* fields: ['title', 'content'],
|
||||
* filters: { status: 'published' },
|
||||
* sort: { createdAt: 'desc' }
|
||||
* };
|
||||
*
|
||||
* // Example: Parameters for creating a new article
|
||||
* const createParams: ArticleServiceParams['create'] = {
|
||||
* data: { title: 'New Article', content: 'Article content', status: 'draft' }
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export type ServiceParams<TContentTypeUID extends UID.ContentType = UID.ContentType> = {
|
||||
/** Parameters for finding multiple documents */
|
||||
findMany: Params.FindMany<TContentTypeUID>;
|
||||
|
||||
/** Parameters for finding a single document */
|
||||
findFirst: Params.FindFirst<TContentTypeUID>;
|
||||
|
||||
/** Parameters for finding a single document by its ID */
|
||||
findOne: Params.FindOne<TContentTypeUID>;
|
||||
|
||||
/** Parameters for deleting a single document */
|
||||
delete: Params.Delete<TContentTypeUID>;
|
||||
|
||||
/** Parameters for creating a new document */
|
||||
create: Params.Create<TContentTypeUID>;
|
||||
|
||||
/** Parameters for cloning an existing document */
|
||||
clone: Params.Clone<TContentTypeUID>;
|
||||
|
||||
/** Parameters for updating an existing document */
|
||||
update: Params.Update<TContentTypeUID>;
|
||||
|
||||
/** Parameters for counting the number of documents */
|
||||
count: Params.Count<TContentTypeUID>;
|
||||
|
||||
/** Parameters for publishing a document */
|
||||
publish: Params.Publish<TContentTypeUID>;
|
||||
|
||||
/** Parameters for unpublishing a document */
|
||||
unpublish: Params.Unpublish<TContentTypeUID>;
|
||||
|
||||
/** Parameters for discarding a draft of a document */
|
||||
discardDraft: Params.DiscardDraft<TContentTypeUID>;
|
||||
};
|
||||
|
||||
@ -1,4 +1,52 @@
|
||||
import type * as UID from '../../../uid';
|
||||
import type * as AttributeUtils from './attributes';
|
||||
|
||||
/**
|
||||
* Represents the input data for a given content-type UID.
|
||||
*
|
||||
* This type evaluates the schema based on the given content-type UID, and extracts the attribute values
|
||||
* accordingly.
|
||||
*
|
||||
* It combines optional and required attributes, while excluding certain relational attributes
|
||||
* that don't target specific schemas like polymorphic relations.
|
||||
*
|
||||
* @template TSchemaUID - A unique identifier for a schema, extending {@link UID.Schema}.
|
||||
*
|
||||
* @remark
|
||||
* The attributes' values are customized to allow additional input formats that are going to be
|
||||
* transformed in the document service methods.
|
||||
*
|
||||
* For example, relational attributes can use the re-ordering API.
|
||||
*
|
||||
* @example
|
||||
* Defining input for a content type schema:
|
||||
*
|
||||
* ```typescript
|
||||
* import type { UID } from '@strapi/types';
|
||||
*
|
||||
* // Assume there's a schema with a UID of 'api::article.article'
|
||||
* type ArticleInput = Input<'api::article.article'>;
|
||||
*
|
||||
* // Example usage of ArticleInput with typed attributes
|
||||
* const articleData: ArticleInput = {
|
||||
* title: 'My Article', // Required title property
|
||||
* content: 'Content of the article', // Required content property
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* Handling component schema with optional and required attributes:
|
||||
*
|
||||
* ```typescript
|
||||
* import type { UID } from '@strapi/types';
|
||||
*
|
||||
* // Assume there's a component with a UID of 'default.comment'
|
||||
* type CommentInput = Input<'default.comment'>;
|
||||
*
|
||||
* const commentData: CommentInput = {
|
||||
* text: 'Great article!', // Required text property
|
||||
* author: 'John Doe', // Optional author property
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export type Input<TSchemaUID extends UID.Schema> = AttributeUtils.GetValues<TSchemaUID>;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user