From 103dfe1ca0e49e32278b625e5ffdfd78089b1ed5 Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Mon, 2 Dec 2024 23:09:36 +0200 Subject: [PATCH] feat: add `findVersions` `findVersionByID` `restoreVersion` `findGlobalVersrions` `findGlobalVersionByID` `restoreGlobalVersion` operations --- docs/rest-api/overview.mdx | 29 +++++++ .../sdk/src/collections/findVersionByID.ts | 58 +++++++++++++ packages/sdk/src/collections/findVersions.ts | 45 ++++++++++ .../sdk/src/collections/restoreVersion.ts | 39 +++++++++ packages/sdk/src/globals/findVersionByID.ts | 58 +++++++++++++ packages/sdk/src/globals/findVersions.ts | 45 ++++++++++ packages/sdk/src/globals/restoreVersion.ts | 43 ++++++++++ packages/sdk/src/index.ts | 58 ++++++++++++- test/sdk/collections/Posts.ts | 1 + test/sdk/config.ts | 1 + test/sdk/int.spec.ts | 83 +++++++++++++++++++ 11 files changed, 459 insertions(+), 1 deletion(-) create mode 100644 packages/sdk/src/collections/findVersionByID.ts create mode 100644 packages/sdk/src/collections/findVersions.ts create mode 100644 packages/sdk/src/collections/restoreVersion.ts create mode 100644 packages/sdk/src/globals/findVersionByID.ts create mode 100644 packages/sdk/src/globals/findVersions.ts create mode 100644 packages/sdk/src/globals/restoreVersion.ts diff --git a/docs/rest-api/overview.mdx b/docs/rest-api/overview.mdx index c485c0657ed..0c3db0eaa56 100644 --- a/docs/rest-api/overview.mdx +++ b/docs/rest-api/overview.mdx @@ -880,6 +880,35 @@ const result = await sdk.resetPassword({ collection: 'users', data: { password: '1234567', token: resetPasswordToken }, }) + +// Find Versions operation +const result = await sdk.findVersions({ + collection: 'posts', + where: { parent: { equals: post.id } }, +}) + +// Find Version by ID operation +const result = await sdk.findVersionByID({ collection: 'posts', id: version.id }) + +// Restore Version operation +const result = await sdk.restoreVersion({ + collection: 'posts', + id, +}) + +// Find Global Versions operation +const result = await sdk.findGlobalVersions({ + slug: 'global', +}) + +// Find Global Version by ID operation +const result = await sdk.findGlobalVersionByID({ id: version.id, slug: 'global' }) + +// Restore Global Version operation +const result = await sdk.restoreGlobalVersion({ + slug: 'global', + id +}) ``` diff --git a/packages/sdk/src/collections/findVersionByID.ts b/packages/sdk/src/collections/findVersionByID.ts new file mode 100644 index 00000000000..304ec929189 --- /dev/null +++ b/packages/sdk/src/collections/findVersionByID.ts @@ -0,0 +1,58 @@ +import type { ApplyDisableErrors, SelectType, TypeWithVersion } from 'payload' + +import type { PayloadSDK } from '../index.js' +import type { + CollectionSlug, + DataFromCollectionSlug, + PayloadGeneratedTypes, + PopulateType, + TypedLocale, +} from '../types.js' + +export type FindVersionByIDOptions< + T extends PayloadGeneratedTypes, + TSlug extends CollectionSlug, + TDisableErrors extends boolean, +> = { + collection: TSlug + depth?: number + disableErrors?: TDisableErrors + draft?: boolean + fallbackLocale?: false | TypedLocale + id: number | string + locale?: 'all' | TypedLocale + populate?: PopulateType + select?: SelectType +} + +export async function findVersionByID< + T extends PayloadGeneratedTypes, + TSlug extends CollectionSlug, + TDisableErrors extends boolean, +>( + sdk: PayloadSDK, + options: FindVersionByIDOptions, + init?: RequestInit, +): Promise>, TDisableErrors>> { + try { + const response = await sdk.request({ + args: options, + init, + method: 'GET', + path: `/${options.collection}/versions/${options.id}`, + }) + + if (response.ok) { + return response.json() + } else { + throw new Error() + } + } catch { + if (options.disableErrors) { + // @ts-expect-error generic nullable + return null + } + + throw new Error(`Error retrieving the version document ${options.collection}/${options.id}`) + } +} diff --git a/packages/sdk/src/collections/findVersions.ts b/packages/sdk/src/collections/findVersions.ts new file mode 100644 index 00000000000..98b7b4af369 --- /dev/null +++ b/packages/sdk/src/collections/findVersions.ts @@ -0,0 +1,45 @@ +import type { PaginatedDocs, SelectType, Sort, TypeWithVersion, Where } from 'payload' + +import type { PayloadSDK } from '../index.js' +import type { + CollectionSlug, + DataFromCollectionSlug, + PayloadGeneratedTypes, + PopulateType, + TypedLocale, +} from '../types.js' + +export type FindVersionsOptions< + T extends PayloadGeneratedTypes, + TSlug extends CollectionSlug, +> = { + collection: TSlug + depth?: number + draft?: boolean + fallbackLocale?: false | TypedLocale + limit?: number + locale?: 'all' | TypedLocale + page?: number + populate?: PopulateType + select?: SelectType + sort?: Sort + where?: Where +} + +export async function findVersions< + T extends PayloadGeneratedTypes, + TSlug extends CollectionSlug, +>( + sdk: PayloadSDK, + options: FindVersionsOptions, + init?: RequestInit, +): Promise>>> { + const response = await sdk.request({ + args: options, + init, + method: 'GET', + path: `/${options.collection}/versions`, + }) + + return response.json() +} diff --git a/packages/sdk/src/collections/restoreVersion.ts b/packages/sdk/src/collections/restoreVersion.ts new file mode 100644 index 00000000000..422d33abf3a --- /dev/null +++ b/packages/sdk/src/collections/restoreVersion.ts @@ -0,0 +1,39 @@ +import type { PayloadSDK } from '../index.js' +import type { + CollectionSlug, + DataFromCollectionSlug, + PayloadGeneratedTypes, + PopulateType, + TypedLocale, +} from '../types.js' + +export type RestoreVersionByIDOptions< + T extends PayloadGeneratedTypes, + TSlug extends CollectionSlug, +> = { + collection: TSlug + depth?: number + draft?: boolean + fallbackLocale?: false | TypedLocale + id: number | string + locale?: 'all' | TypedLocale + populate?: PopulateType +} + +export async function restoreVersion< + T extends PayloadGeneratedTypes, + TSlug extends CollectionSlug, +>( + sdk: PayloadSDK, + options: RestoreVersionByIDOptions, + init?: RequestInit, +): Promise> { + const response = await sdk.request({ + args: options, + init, + method: 'POST', + path: `/${options.collection}/versions/${options.id}`, + }) + + return response.json() +} diff --git a/packages/sdk/src/globals/findVersionByID.ts b/packages/sdk/src/globals/findVersionByID.ts new file mode 100644 index 00000000000..9930f5e62c6 --- /dev/null +++ b/packages/sdk/src/globals/findVersionByID.ts @@ -0,0 +1,58 @@ +import type { ApplyDisableErrors, SelectType, TypeWithVersion } from 'payload' + +import type { PayloadSDK } from '../index.js' +import type { + DataFromGlobalSlug, + GlobalSlug, + PayloadGeneratedTypes, + PopulateType, + TypedLocale, +} from '../types.js' + +export type FindGlobalVersionByIDOptions< + T extends PayloadGeneratedTypes, + TSlug extends GlobalSlug, + TDisableErrors extends boolean, +> = { + depth?: number + disableErrors?: TDisableErrors + draft?: boolean + fallbackLocale?: false | TypedLocale + id: number | string + locale?: 'all' | TypedLocale + populate?: PopulateType + select?: SelectType + slug: TSlug +} + +export async function findGlobalVersionByID< + T extends PayloadGeneratedTypes, + TSlug extends GlobalSlug, + TDisableErrors extends boolean, +>( + sdk: PayloadSDK, + options: FindGlobalVersionByIDOptions, + init?: RequestInit, +): Promise>, TDisableErrors>> { + try { + const response = await sdk.request({ + args: options, + init, + method: 'GET', + path: `/globals/${options.slug}/versions/${options.id}`, + }) + + if (response.ok) { + return response.json() + } else { + throw new Error() + } + } catch { + if (options.disableErrors) { + // @ts-expect-error generic nullable + return null + } + + throw new Error(`Error retrieving the version document ${options.slug}/${options.id}`) + } +} diff --git a/packages/sdk/src/globals/findVersions.ts b/packages/sdk/src/globals/findVersions.ts new file mode 100644 index 00000000000..6ecc72f9eef --- /dev/null +++ b/packages/sdk/src/globals/findVersions.ts @@ -0,0 +1,45 @@ +import type { PaginatedDocs, SelectType, Sort, TypeWithVersion, Where } from 'payload' + +import type { PayloadSDK } from '../index.js' +import type { + DataFromGlobalSlug, + GlobalSlug, + PayloadGeneratedTypes, + PopulateType, + TypedLocale, +} from '../types.js' + +export type FindGlobalVersionsOptions< + T extends PayloadGeneratedTypes, + TSlug extends GlobalSlug, +> = { + depth?: number + draft?: boolean + fallbackLocale?: false | TypedLocale + limit?: number + locale?: 'all' | TypedLocale + page?: number + populate?: PopulateType + select?: SelectType + slug: TSlug + sort?: Sort + where?: Where +} + +export async function findGlobalVersions< + T extends PayloadGeneratedTypes, + TSlug extends GlobalSlug, +>( + sdk: PayloadSDK, + options: FindGlobalVersionsOptions, + init?: RequestInit, +): Promise>>> { + const response = await sdk.request({ + args: options, + init, + method: 'GET', + path: `/globals/${options.slug}/versions`, + }) + + return response.json() +} diff --git a/packages/sdk/src/globals/restoreVersion.ts b/packages/sdk/src/globals/restoreVersion.ts new file mode 100644 index 00000000000..2468d350658 --- /dev/null +++ b/packages/sdk/src/globals/restoreVersion.ts @@ -0,0 +1,43 @@ +import type { TypeWithVersion } from 'payload' + +import type { PayloadSDK } from '../index.js' +import type { + DataFromGlobalSlug, + GlobalSlug, + PayloadGeneratedTypes, + PopulateType, + TypedLocale, +} from '../types.js' + +export type RestoreGlobalVersionByIDOptions< + T extends PayloadGeneratedTypes, + TSlug extends GlobalSlug, +> = { + depth?: number + draft?: boolean + fallbackLocale?: false | TypedLocale + id: number | string + locale?: 'all' | TypedLocale + populate?: PopulateType + slug: TSlug +} + +export async function restoreGlobalVersion< + T extends PayloadGeneratedTypes, + TSlug extends GlobalSlug, +>( + sdk: PayloadSDK, + options: RestoreGlobalVersionByIDOptions, + init?: RequestInit, +): Promise>> { + const response = await sdk.request({ + args: options, + init, + method: 'POST', + path: `/globals/${options.slug}/versions/${options.id}`, + }) + + const { doc } = await response.json() + + return doc +} diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index bee01f4ec64..40f805b7ec8 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -1,4 +1,4 @@ -import type { ApplyDisableErrors, PaginatedDocs, SelectType } from 'payload' +import type { ApplyDisableErrors, PaginatedDocs, SelectType, TypeWithVersion } from 'payload' import type { ForgotPasswordOptions } from './auth/forgotPassword.js' import type { LoginOptions, LoginResult } from './auth/login.js' @@ -9,11 +9,19 @@ import type { CreateOptions } from './collections/create.js' import type { DeleteByIDOptions, DeleteManyOptions, DeleteOptions } from './collections/delete.js' import type { FindOptions } from './collections/find.js' import type { FindByIDOptions } from './collections/findByID.js' +import type { FindVersionByIDOptions } from './collections/findVersionByID.js' +import type { FindVersionsOptions } from './collections/findVersions.js' +import type { RestoreVersionByIDOptions } from './collections/restoreVersion.js' +import type { FindGlobalVersionByIDOptions } from './globals/findVersionByID.js' +import type { FindGlobalVersionsOptions } from './globals/findVersions.js' +import type { RestoreGlobalVersionByIDOptions } from './globals/restoreVersion.js' import type { UpdateGlobalOptions } from './globals/update.js' import type { AuthCollectionSlug, BulkOperationResult, CollectionSlug, + DataFromCollectionSlug, + DataFromGlobalSlug, GlobalSlug, PayloadGeneratedTypes, SelectFromCollectionSlug, @@ -34,6 +42,9 @@ import { create } from './collections/create.js' import { deleteOperation } from './collections/delete.js' import { find } from './collections/find.js' import { findByID } from './collections/findByID.js' +import { findVersionByID } from './collections/findVersionByID.js' +import { findVersions } from './collections/findVersions.js' +import { restoreVersion } from './collections/restoreVersion.js' import { update, type UpdateByIDOptions, @@ -41,6 +52,9 @@ import { type UpdateOptions, } from './collections/update.js' import { findGlobal, type FindGlobalOptions } from './globals/findOne.js' +import { findGlobalVersionByID } from './globals/findVersionByID.js' +import { findGlobalVersions } from './globals/findVersions.js' +import { restoreGlobalVersion } from './globals/restoreVersion.js' import { updateGlobal } from './globals/update.js' import { buildSearchParams } from './utilities/buildSearchParams.js' @@ -199,6 +213,34 @@ export class PayloadSDK return findGlobal(this, options, init) } + findGlobalVersionByID, TDisableErrors extends boolean>( + options: FindGlobalVersionByIDOptions, + init?: RequestInit, + ): Promise>, TDisableErrors>> { + return findGlobalVersionByID(this, options, init) + } + + findGlobalVersions>( + options: FindGlobalVersionsOptions, + init?: RequestInit, + ): Promise>>> { + return findGlobalVersions(this, options, init) + } + findVersionByID, TDisableErrors extends boolean>( + options: FindVersionByIDOptions, + init?: RequestInit, + ): Promise< + ApplyDisableErrors>, TDisableErrors> + > { + return findVersionByID(this, options, init) + } + + findVersions>( + options: FindVersionsOptions, + init?: RequestInit, + ): Promise>>> { + return findVersions(this, options, init) + } forgotPassword>( options: ForgotPasswordOptions, init?: RequestInit, @@ -275,6 +317,20 @@ export class PayloadSDK return resetPassword(this, options, init) } + restoreGlobalVersion>( + options: RestoreGlobalVersionByIDOptions, + init?: RequestInit, + ): Promise>> { + return restoreGlobalVersion(this, options, init) + } + + restoreVersion>( + options: RestoreVersionByIDOptions, + init?: RequestInit, + ): Promise> { + return restoreVersion(this, options, init) + } + update, TSelect extends SelectFromCollectionSlug>( options: UpdateManyOptions, init?: RequestInit, diff --git a/test/sdk/collections/Posts.ts b/test/sdk/collections/Posts.ts index 102bb803d2a..28b474f78db 100644 --- a/test/sdk/collections/Posts.ts +++ b/test/sdk/collections/Posts.ts @@ -36,4 +36,5 @@ export const PostsCollection: CollectionConfig = { ], }, ], + versions: true, } diff --git a/test/sdk/config.ts b/test/sdk/config.ts index 0cb5e2b764a..5767c2cbffc 100644 --- a/test/sdk/config.ts +++ b/test/sdk/config.ts @@ -28,6 +28,7 @@ export default buildConfigWithDefaults({ { slug: 'global', fields: [{ type: 'text', name: 'text' }], + versions: true, }, ], localization: { diff --git a/test/sdk/int.spec.ts b/test/sdk/int.spec.ts index 805e12152bf..2a34806b0e8 100644 --- a/test/sdk/int.spec.ts +++ b/test/sdk/int.spec.ts @@ -47,6 +47,15 @@ describe('@payloadcms/sdk', () => { expect(result.docs[0].id).toBe(post.id) }) + it('should execute findVersions', async () => { + const result = await sdk.findVersions({ + collection: 'posts', + where: { parent: { equals: post.id } }, + }) + + expect(result.docs[0].parent).toBe(post.id) + }) + it('should execute findByID', async () => { const result = await sdk.findByID({ collection: 'posts', id: post.id }) @@ -64,6 +73,16 @@ describe('@payloadcms/sdk', () => { expect(result).toBeNull() }) + it('should execute findVersionByID', async () => { + const { + docs: [version], + } = await payload.findVersions({ collection: 'posts', where: { parent: { equals: post.id } } }) + + const result = await sdk.findVersionByID({ collection: 'posts', id: version.id }) + + expect(result.id).toBe(version.id) + }) + it('should execute create', async () => { const result = await sdk.create({ collection: 'posts', data: { text: 'text' } }) @@ -140,16 +159,80 @@ describe('@payloadcms/sdk', () => { expect(resultLocal).toBeNull() }) + it('should execute restoreVersion', async () => { + const post = await payload.create({ collection: 'posts', data: { text: 'old' } }) + + const { + docs: [currentVersion], + } = await payload.findVersions({ collection: 'posts', where: { parent: { equals: post.id } } }) + + await payload.update({ collection: 'posts', id: post.id, data: { text: 'new' } }) + + const result = await sdk.restoreVersion({ + collection: 'posts', + id: currentVersion.id, + }) + + expect(result.text).toBe('old') + + const resultDB = await payload.findByID({ collection: 'posts', id: post.id }) + + expect(resultDB.text).toBe('old') + }) + it('should execute findGlobal', async () => { const result = await sdk.findGlobal({ slug: 'global' }) expect(result.text).toBe('some-global') }) + it('should execute findGlobalVersions', async () => { + const result = await sdk.findGlobalVersions({ + slug: 'global', + }) + + expect(result.docs[0].version).toBeTruthy() + }) + + it('should execute findGlobalVersionByID', async () => { + const { + docs: [version], + } = await payload.findGlobalVersions({ + slug: 'global', + }) + + const result = await sdk.findGlobalVersionByID({ id: version.id, slug: 'global' }) + + expect(result.id).toBe(version.id) + }) + it('should execute updateGlobal', async () => { const result = await sdk.updateGlobal({ slug: 'global', data: { text: 'some-updated-global' } }) expect(result.text).toBe('some-updated-global') }) + it('should execute restoreGlobalVersion', async () => { + await payload.updateGlobal({ slug: 'global', data: { text: 'old' } }) + + const { + docs: [currentVersion], + } = await payload.findGlobalVersions({ + slug: 'global', + }) + + await payload.updateGlobal({ slug: 'global', data: { text: 'new' } }) + + const { version: result } = await sdk.restoreGlobalVersion({ + slug: 'global', + id: currentVersion.id, + }) + + expect(result.text).toBe('old') + + const resultDB = await payload.findGlobal({ slug: 'global' }) + + expect(resultDB.text).toBe('old') + }) + it('should execute login', async () => { const res = await sdk.login({ collection: 'users',