From 843482b6b17f8f90d4388ec08100eab1f2bd6a56 Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Fri, 17 Oct 2025 13:29:40 -0400 Subject: [PATCH 1/4] feat: create use case for collection template --- CHANGELOG.md | 1 + docs/useCases.md | 36 +++++++++++ .../domain/dtos/TemplateCreateDTO.ts | 45 ++++++++++++++ .../repositories/ICollectionsRepository.ts | 2 + .../domain/useCases/CreateTemplate.ts | 26 ++++++++ src/collections/index.ts | 5 +- .../repositories/CollectionsRepository.ts | 15 +++++ .../collections/CreateTemplate.test.ts | 62 +++++++++++++++++++ .../collections/CollectionsRepository.test.ts | 62 ++++++++++++++++++- test/unit/collections/CreateTemplate.test.ts | 43 +++++++++++++ 10 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 src/collections/domain/dtos/TemplateCreateDTO.ts create mode 100644 src/collections/domain/useCases/CreateTemplate.ts create mode 100644 test/functional/collections/CreateTemplate.test.ts create mode 100644 test/unit/collections/CreateTemplate.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 57ea977c..c84c5d99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This changelog follows the principles of [Keep a Changelog](https://keepachangel ### Added - New Use Case: [Get Collections For Linking Use Case](./docs/useCases.md#get-collections-for-linking). +- New Use Case: [Create a Template](./docs/useCases.md#create-a-template) under Collections. ### Changed diff --git a/docs/useCases.md b/docs/useCases.md index 6d5565fe..6ebb8dbe 100644 --- a/docs/useCases.md +++ b/docs/useCases.md @@ -18,6 +18,7 @@ The different use cases currently available in the package are classified below, - [Get Collection Featured Items](#get-collection-featured-items) - [Get Collections for Linking](#get-collections-for-linking) - [Collections write use cases](#collections-write-use-cases) + - [Create a Template](#create-a-template) - [Create a Collection](#create-a-collection) - [Update a Collection](#update-a-collection) - [Publish a Collection](#publish-a-collection) @@ -567,6 +568,41 @@ deleteCollectionFeaturedItem.execute(featuredItemId) _See [use case](../src/collections/domain/useCases/DeleteCollectionFeaturedItem.ts)_ definition. +#### Create a Template + +Creates a template for a given Dataverse collection id or alias. + +##### Example call: + +```typescript +import { createTemplate } from '@iqss/dataverse-client-javascript' +import { TemplateCreateDTO } from '@iqss/dataverse-client-javascript' + +const collectionAlias = ':root' +const template: TemplateCreateDTO = { + name: 'Dataverse template', + isDefault: true, + fields: [ + { + typeName: 'author', + typeClass: 'compound', + multiple: true, + value: [ + { + authorName: { typeName: 'authorName', value: 'Belicheck, Bill' }, + authorAffiliation: { typeName: 'authorIdentifierScheme', value: 'ORCID' } + } + ] + } + ], + instructions: [{ instructionField: 'author', instructionText: 'The author data' }] +} + +await createTemplate.execute(template, collectionAlias) +``` + +_See [use case](../src/collections/domain/useCases/CreateTemplate.ts) implementation_. + ## Datasets ### Datasets Read Use Cases diff --git a/src/collections/domain/dtos/TemplateCreateDTO.ts b/src/collections/domain/dtos/TemplateCreateDTO.ts new file mode 100644 index 00000000..e3fcccb8 --- /dev/null +++ b/src/collections/domain/dtos/TemplateCreateDTO.ts @@ -0,0 +1,45 @@ +import { MetadataFieldTypeClass } from '../../../metadataBlocks/domain/models/MetadataBlock' + +export interface TemplateCreateDTO { + name: string + isDefault: boolean | false // defaults to false if not provided + fields?: TemplateFieldDTO[] + instructions?: TemplateInstructionDTO[] +} + +export interface TemplateFieldDTO { + typeName: string + multiple: boolean + typeClass: MetadataFieldTypeClass + value: TemplateFieldValueDTO[] +} + +export interface TemplateFieldValueDTO { + [key: string]: + | TemplateFieldValuePrimitiveDTO + | TemplateFieldValueCompoundDTO + | TemplateFieldValueControlledVocabularyDTO +} + +export interface TemplateFieldValuePrimitiveDTO { + typeName: string + typeClass: MetadataFieldTypeClass.Primitive + value: string | string[] +} + +export interface TemplateFieldValueCompoundDTO { + typeName: string + typeClass: MetadataFieldTypeClass.Compound + value: TemplateFieldValueDTO[] +} + +export interface TemplateFieldValueControlledVocabularyDTO { + typeName: string + typeClass: MetadataFieldTypeClass.ControlledVocabulary + value: string +} + +export interface TemplateInstructionDTO { + instructionField: string + instructionText: string +} diff --git a/src/collections/domain/repositories/ICollectionsRepository.ts b/src/collections/domain/repositories/ICollectionsRepository.ts index bc8960c8..ded23958 100644 --- a/src/collections/domain/repositories/ICollectionsRepository.ts +++ b/src/collections/domain/repositories/ICollectionsRepository.ts @@ -12,6 +12,7 @@ import { CollectionItemType } from '../../../collections/domain/models/Collectio import { CollectionLinks } from '../models/CollectionLinks' import { CollectionSummary } from '../models/CollectionSummary' import { LinkingObjectType } from '../useCases/GetCollectionsForLinking' +import { TemplateCreateDTO } from '../dtos/TemplateCreateDTO' export interface ICollectionsRepository { getCollection(collectionIdOrAlias: number | string): Promise @@ -68,4 +69,5 @@ export interface ICollectionsRepository { searchTerm: string, alreadyLinked: boolean ): Promise + createTemplate(collectionIdOrAlias: number | string, template: TemplateCreateDTO): Promise } diff --git a/src/collections/domain/useCases/CreateTemplate.ts b/src/collections/domain/useCases/CreateTemplate.ts new file mode 100644 index 00000000..1a6b243c --- /dev/null +++ b/src/collections/domain/useCases/CreateTemplate.ts @@ -0,0 +1,26 @@ +import { ROOT_COLLECTION_ID } from '../models/Collection' +import { UseCase } from '../../../core/domain/useCases/UseCase' +import { ICollectionsRepository } from '../repositories/ICollectionsRepository' +import { TemplateCreateDTO } from '../dtos/TemplateCreateDTO' + +export class CreateTemplate implements UseCase { + private collectionsRepository: ICollectionsRepository + + constructor(collectionsRepository: ICollectionsRepository) { + this.collectionsRepository = collectionsRepository + } + + /** + * Creates a Dataset Template in the specified collection. + * + * @param {TemplateCreateDTO} template - Template definition payload. + * @param {number | string} [collectionIdOrAlias = ':root'] - Target collection id or alias. + * @returns {Promise} + */ + async execute( + template: TemplateCreateDTO, + collectionIdOrAlias: number | string = ROOT_COLLECTION_ID + ): Promise { + return await this.collectionsRepository.createTemplate(collectionIdOrAlias, template) + } +} diff --git a/src/collections/index.ts b/src/collections/index.ts index 59e2e50b..6e74032d 100644 --- a/src/collections/index.ts +++ b/src/collections/index.ts @@ -16,6 +16,7 @@ import { LinkCollection } from './domain/useCases/LinkCollection' import { UnlinkCollection } from './domain/useCases/UnlinkCollection' import { GetCollectionLinks } from './domain/useCases/GetCollectionLinks' import { GetCollectionsForLinking } from './domain/useCases/GetCollectionsForLinking' +import { CreateTemplate } from './domain/useCases/CreateTemplate' const collectionsRepository = new CollectionsRepository() @@ -36,6 +37,7 @@ const linkCollection = new LinkCollection(collectionsRepository) const unlinkCollection = new UnlinkCollection(collectionsRepository) const getCollectionLinks = new GetCollectionLinks(collectionsRepository) const getCollectionsForLinking = new GetCollectionsForLinking(collectionsRepository) +const createTemplate = new CreateTemplate(collectionsRepository) export { getCollection, @@ -54,7 +56,8 @@ export { linkCollection, unlinkCollection, getCollectionLinks, - getCollectionsForLinking + getCollectionsForLinking, + createTemplate } export { Collection, CollectionInputLevel } from './domain/models/Collection' export { CollectionFacet } from './domain/models/CollectionFacet' diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index e0e459b0..1a71f061 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -40,6 +40,7 @@ import { ReadError } from '../../../core/domain/repositories/ReadError' import { CollectionLinks } from '../../domain/models/CollectionLinks' import { CollectionSummary } from '../../domain/models/CollectionSummary' import { LinkingObjectType } from '../../domain/useCases/GetCollectionsForLinking' +import { TemplateCreateDTO } from '../../domain/dtos/TemplateCreateDTO' export interface NewCollectionRequestPayload { alias: string @@ -528,4 +529,18 @@ export class CollectionsRepository extends ApiRepository implements ICollections throw error }) } + + public async createTemplate( + collectionIdOrAlias: number | string, + template: TemplateCreateDTO + ): Promise { + return this.doPost( + `/${this.collectionsResourceName}/${collectionIdOrAlias}/templates`, + template + ) + .then(() => undefined) + .catch((error) => { + throw error + }) + } } diff --git a/test/functional/collections/CreateTemplate.test.ts b/test/functional/collections/CreateTemplate.test.ts new file mode 100644 index 00000000..cd4486ab --- /dev/null +++ b/test/functional/collections/CreateTemplate.test.ts @@ -0,0 +1,62 @@ +import { ApiConfig } from '../../../src' +import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig' +import { TestConstants } from '../../testHelpers/TestConstants' +import { getDatasetTemplates } from '../../../src/datasets' +import { TemplateCreateDTO } from '../../../src/collections/domain/dtos/TemplateCreateDTO' +import { createTemplate } from '../../../src/collections' +import { MetadataFieldTypeClass } from '../../../src/metadataBlocks/domain/models/MetadataBlock' +import { deleteDatasetTemplateViaApi } from '../../testHelpers/datasets/datasetTemplatesHelper' + +describe('CreateTemplate.execute', () => { + beforeEach(async () => { + ApiConfig.init( + TestConstants.TEST_API_URL, + DataverseApiAuthMechanism.API_KEY, + process.env.TEST_API_KEY + ) + }) + + test('should create a template in :root with provided JSON', async () => { + const templateDto: TemplateCreateDTO = { + name: 'TestDataverse template', + isDefault: true, + fields: [ + { + typeName: 'author', + typeClass: MetadataFieldTypeClass.Compound, + multiple: true, + value: [ + { + authorName: { + typeName: 'authorName', + typeClass: MetadataFieldTypeClass.Primitive, + value: 'Belicheck, Bill' + }, + authorAffiliation: { + typeName: 'authorIdentifierScheme', + typeClass: MetadataFieldTypeClass.Primitive, + value: 'ORCID' + } + } + ] + } + ], + instructions: [ + { + instructionField: 'author', + instructionText: 'The author data' + } + ] + } + await createTemplate.execute(templateDto) + const templates = await getDatasetTemplates.execute(':root') + + expect(templates[templates.length - 1].name).toBe(templateDto.name) + expect(templates[templates.length - 1].isDefault).toBe(templateDto.isDefault) + expect(templates[templates.length - 1].instructions.length).toBe( + templateDto.instructions?.length ?? 0 + ) + + deleteDatasetTemplateViaApi(templates[templates.length - 1].id) + }) +}) diff --git a/test/integration/collections/CollectionsRepository.test.ts b/test/integration/collections/CollectionsRepository.test.ts index 1d6041b6..4cd43517 100644 --- a/test/integration/collections/CollectionsRepository.test.ts +++ b/test/integration/collections/CollectionsRepository.test.ts @@ -16,7 +16,9 @@ import { getDatasetFiles, restrictFile, deleteFile, - linkDataset + linkDataset, + createTemplate, + MetadataFieldTypeClass } from '../../../src' import { ApiConfig } from '../../../src' import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig' @@ -58,6 +60,9 @@ import { DvObjectFeaturedItemDTO, FeaturedItemsDTO } from '../../../src/collections/domain/dtos/FeaturedItemsDTO' +import { TemplateCreateDTO } from '../../../src/collections/domain/dtos/TemplateCreateDTO' +import { getDatasetTemplates } from '../../../src/datasets' +import { deleteDatasetTemplateViaApi } from '../../testHelpers/datasets/datasetTemplatesHelper' describe('CollectionsRepository', () => { const testCollectionAlias = 'collectionsRepositoryTestCollection' @@ -2143,4 +2148,59 @@ describe('CollectionsRepository', () => { await expect(sut.getCollectionLinks(invalidCollectionId)).rejects.toThrow(expectedError) }) }) + + describe('createTemplate', () => { + const templateDto: TemplateCreateDTO = { + name: 'CollectionsRepository template', + isDefault: true, + fields: [ + { + typeName: 'author', + typeClass: MetadataFieldTypeClass.Compound, + multiple: true, + value: [ + { + authorName: { + typeName: 'authorName', + typeClass: MetadataFieldTypeClass.Primitive, + value: 'Belicheck, Bill' + }, + authorAffiliation: { + typeName: 'authorIdentifierScheme', + typeClass: MetadataFieldTypeClass.Primitive, + value: 'ORCID' + } + } + ] + } + ], + instructions: [ + { + instructionField: 'author', + instructionText: 'The author data' + } + ] + } + test('should create a template in :root with provided JSON', async () => { + await createTemplate.execute(templateDto) + const templates = await getDatasetTemplates.execute(':root') + + expect(templates[templates.length - 1].name).toBe(templateDto.name) + expect(templates[templates.length - 1].isDefault).toBe(templateDto.isDefault) + expect(templates[templates.length - 1].instructions.length).toBe( + templateDto.instructions?.length ?? 0 + ) + + deleteDatasetTemplateViaApi(templates[templates.length - 1].id) + }) + + test('should return error when creating a template with invalidCollectionAlias', async () => { + const expectedError = new WriteError( + `[404] Can't find dataverse with identifier='invalidCollectionAlias'` + ) + await expect(createTemplate.execute(templateDto, 'invalidCollectionAlias')).rejects.toThrow( + expectedError + ) + }) + }) }) diff --git a/test/unit/collections/CreateTemplate.test.ts b/test/unit/collections/CreateTemplate.test.ts new file mode 100644 index 00000000..89c8d64b --- /dev/null +++ b/test/unit/collections/CreateTemplate.test.ts @@ -0,0 +1,43 @@ +import { CreateTemplate } from '../../../src/collections/domain/useCases/CreateTemplate' +import { ICollectionsRepository } from '../../../src/collections/domain/repositories/ICollectionsRepository' +import { TemplateCreateDTO } from '../../../src/collections/domain/dtos/TemplateCreateDTO' +import { WriteError } from '../../../src' + +describe('execute', () => { + const testTemplateDTO = { name: 't' } as TemplateCreateDTO + const testCollectionId = 1 + + test('should return undefined when repository call is successful', async () => { + const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository + collectionRepositoryStub.createTemplate = jest.fn().mockResolvedValue(testCollectionId) + const sut = new CreateTemplate(collectionRepositoryStub) + + const actual = await sut.execute(testTemplateDTO) + + expect(collectionRepositoryStub.createTemplate).toHaveBeenCalledWith(':root', testTemplateDTO) + expect(actual).toEqual(testCollectionId) + }) + + test('should call repository with provided collection id/alias', async () => { + const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository + collectionRepositoryStub.createTemplate = jest.fn().mockResolvedValue(testCollectionId) + + const sut = new CreateTemplate(collectionRepositoryStub) + const actual = await sut.execute(testTemplateDTO, 'alias123') + + expect(collectionRepositoryStub.createTemplate).toHaveBeenCalledWith( + 'alias123', + testTemplateDTO + ) + + expect(actual).toEqual(testCollectionId) + }) + + test('should return error result on repository error', async () => { + const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository + collectionRepositoryStub.createTemplate = jest.fn().mockRejectedValue(new WriteError()) + const testCreateTemplate = new CreateTemplate(collectionRepositoryStub) + + await expect(testCreateTemplate.execute(testTemplateDTO)).rejects.toThrow(WriteError) + }) +}) From fdaa4a62ee12cc7f3bd677f9bcf62a0d7632aa73 Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Wed, 22 Oct 2025 16:58:30 -0400 Subject: [PATCH 2/4] fix: making changes based on reviews --- docs/useCases.md | 12 +++++------ .../domain/dtos/TemplateCreateDTO.ts | 6 +++--- .../repositories/ICollectionsRepository.ts | 5 ++++- ...teTemplate.ts => CreateDatasetTemplate.ts} | 7 ++++--- src/collections/index.ts | 6 +++--- .../repositories/CollectionsRepository.ts | 2 +- ....test.ts => createDatasetTemplate.test.ts} | 4 ++-- .../collections/CollectionsRepository.test.ts | 12 +++++------ ...plate.test.ts => createDatasetTemplate.ts} | 21 +++++++++++-------- 9 files changed, 41 insertions(+), 34 deletions(-) rename src/collections/domain/useCases/{CreateTemplate.ts => CreateDatasetTemplate.ts} (69%) rename test/functional/collections/{CreateTemplate.test.ts => createDatasetTemplate.test.ts} (94%) rename test/unit/collections/{CreateTemplate.test.ts => createDatasetTemplate.ts} (60%) diff --git a/docs/useCases.md b/docs/useCases.md index 6ebb8dbe..d0dedb42 100644 --- a/docs/useCases.md +++ b/docs/useCases.md @@ -18,7 +18,7 @@ The different use cases currently available in the package are classified below, - [Get Collection Featured Items](#get-collection-featured-items) - [Get Collections for Linking](#get-collections-for-linking) - [Collections write use cases](#collections-write-use-cases) - - [Create a Template](#create-a-template) + - [Create a Dataset Template](#create-a-dataset-template) - [Create a Collection](#create-a-collection) - [Update a Collection](#update-a-collection) - [Publish a Collection](#publish-a-collection) @@ -568,14 +568,14 @@ deleteCollectionFeaturedItem.execute(featuredItemId) _See [use case](../src/collections/domain/useCases/DeleteCollectionFeaturedItem.ts)_ definition. -#### Create a Template +#### Create a Dataset Template -Creates a template for a given Dataverse collection id or alias. +Creates a dataset template for a given Dataverse collection id or alias. ##### Example call: ```typescript -import { createTemplate } from '@iqss/dataverse-client-javascript' +import { createDatasetTemplate } from '@iqss/dataverse-client-javascript' import { TemplateCreateDTO } from '@iqss/dataverse-client-javascript' const collectionAlias = ':root' @@ -598,10 +598,10 @@ const template: TemplateCreateDTO = { instructions: [{ instructionField: 'author', instructionText: 'The author data' }] } -await createTemplate.execute(template, collectionAlias) +await createDatasetTemplate.execute(template, collectionAlias) ``` -_See [use case](../src/collections/domain/useCases/CreateTemplate.ts) implementation_. +_See [use case](../src/collections/domain/useCases/CreateDatasetTemplate.ts) implementation_. ## Datasets diff --git a/src/collections/domain/dtos/TemplateCreateDTO.ts b/src/collections/domain/dtos/TemplateCreateDTO.ts index e3fcccb8..a8b729b1 100644 --- a/src/collections/domain/dtos/TemplateCreateDTO.ts +++ b/src/collections/domain/dtos/TemplateCreateDTO.ts @@ -2,7 +2,7 @@ import { MetadataFieldTypeClass } from '../../../metadataBlocks/domain/models/Me export interface TemplateCreateDTO { name: string - isDefault: boolean | false // defaults to false if not provided + isDefault?: boolean fields?: TemplateFieldDTO[] instructions?: TemplateInstructionDTO[] } @@ -10,8 +10,8 @@ export interface TemplateCreateDTO { export interface TemplateFieldDTO { typeName: string multiple: boolean - typeClass: MetadataFieldTypeClass - value: TemplateFieldValueDTO[] + typeClass?: MetadataFieldTypeClass + value?: TemplateFieldValueDTO[] } export interface TemplateFieldValueDTO { diff --git a/src/collections/domain/repositories/ICollectionsRepository.ts b/src/collections/domain/repositories/ICollectionsRepository.ts index ded23958..432749a0 100644 --- a/src/collections/domain/repositories/ICollectionsRepository.ts +++ b/src/collections/domain/repositories/ICollectionsRepository.ts @@ -69,5 +69,8 @@ export interface ICollectionsRepository { searchTerm: string, alreadyLinked: boolean ): Promise - createTemplate(collectionIdOrAlias: number | string, template: TemplateCreateDTO): Promise + createDatasetTemplate( + collectionIdOrAlias: number | string, + template: TemplateCreateDTO + ): Promise } diff --git a/src/collections/domain/useCases/CreateTemplate.ts b/src/collections/domain/useCases/CreateDatasetTemplate.ts similarity index 69% rename from src/collections/domain/useCases/CreateTemplate.ts rename to src/collections/domain/useCases/CreateDatasetTemplate.ts index 1a6b243c..4236332d 100644 --- a/src/collections/domain/useCases/CreateTemplate.ts +++ b/src/collections/domain/useCases/CreateDatasetTemplate.ts @@ -3,7 +3,7 @@ import { UseCase } from '../../../core/domain/useCases/UseCase' import { ICollectionsRepository } from '../repositories/ICollectionsRepository' import { TemplateCreateDTO } from '../dtos/TemplateCreateDTO' -export class CreateTemplate implements UseCase { +export class CreateDatasetTemplate implements UseCase { private collectionsRepository: ICollectionsRepository constructor(collectionsRepository: ICollectionsRepository) { @@ -14,13 +14,14 @@ export class CreateTemplate implements UseCase { * Creates a Dataset Template in the specified collection. * * @param {TemplateCreateDTO} template - Template definition payload. - * @param {number | string} [collectionIdOrAlias = ':root'] - Target collection id or alias. + * @param {number | string} [collectionIdOrAlias = ':root'] - A generic collection identifier, which can be either a string (for queries by CollectionAlias), or a number (for queries by CollectionId) + * If this parameter is not set, the default value is: ':root'. * @returns {Promise} */ async execute( template: TemplateCreateDTO, collectionIdOrAlias: number | string = ROOT_COLLECTION_ID ): Promise { - return await this.collectionsRepository.createTemplate(collectionIdOrAlias, template) + return await this.collectionsRepository.createDatasetTemplate(collectionIdOrAlias, template) } } diff --git a/src/collections/index.ts b/src/collections/index.ts index 6e74032d..df7b6af5 100644 --- a/src/collections/index.ts +++ b/src/collections/index.ts @@ -16,7 +16,7 @@ import { LinkCollection } from './domain/useCases/LinkCollection' import { UnlinkCollection } from './domain/useCases/UnlinkCollection' import { GetCollectionLinks } from './domain/useCases/GetCollectionLinks' import { GetCollectionsForLinking } from './domain/useCases/GetCollectionsForLinking' -import { CreateTemplate } from './domain/useCases/CreateTemplate' +import { CreateDatasetTemplate } from './domain/useCases/CreateDatasetTemplate' const collectionsRepository = new CollectionsRepository() @@ -37,7 +37,7 @@ const linkCollection = new LinkCollection(collectionsRepository) const unlinkCollection = new UnlinkCollection(collectionsRepository) const getCollectionLinks = new GetCollectionLinks(collectionsRepository) const getCollectionsForLinking = new GetCollectionsForLinking(collectionsRepository) -const createTemplate = new CreateTemplate(collectionsRepository) +const createDatasetTemplate = new CreateDatasetTemplate(collectionsRepository) export { getCollection, @@ -57,7 +57,7 @@ export { unlinkCollection, getCollectionLinks, getCollectionsForLinking, - createTemplate + createDatasetTemplate } export { Collection, CollectionInputLevel } from './domain/models/Collection' export { CollectionFacet } from './domain/models/CollectionFacet' diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index 1a71f061..62c8d936 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -530,7 +530,7 @@ export class CollectionsRepository extends ApiRepository implements ICollections }) } - public async createTemplate( + public async createDatasetTemplate( collectionIdOrAlias: number | string, template: TemplateCreateDTO ): Promise { diff --git a/test/functional/collections/CreateTemplate.test.ts b/test/functional/collections/createDatasetTemplate.test.ts similarity index 94% rename from test/functional/collections/CreateTemplate.test.ts rename to test/functional/collections/createDatasetTemplate.test.ts index cd4486ab..bf89e319 100644 --- a/test/functional/collections/CreateTemplate.test.ts +++ b/test/functional/collections/createDatasetTemplate.test.ts @@ -3,7 +3,7 @@ import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ import { TestConstants } from '../../testHelpers/TestConstants' import { getDatasetTemplates } from '../../../src/datasets' import { TemplateCreateDTO } from '../../../src/collections/domain/dtos/TemplateCreateDTO' -import { createTemplate } from '../../../src/collections' +import { createDatasetTemplate } from '../../../src/collections' import { MetadataFieldTypeClass } from '../../../src/metadataBlocks/domain/models/MetadataBlock' import { deleteDatasetTemplateViaApi } from '../../testHelpers/datasets/datasetTemplatesHelper' @@ -48,7 +48,7 @@ describe('CreateTemplate.execute', () => { } ] } - await createTemplate.execute(templateDto) + await createDatasetTemplate.execute(templateDto) const templates = await getDatasetTemplates.execute(':root') expect(templates[templates.length - 1].name).toBe(templateDto.name) diff --git a/test/integration/collections/CollectionsRepository.test.ts b/test/integration/collections/CollectionsRepository.test.ts index 4cd43517..b82afca7 100644 --- a/test/integration/collections/CollectionsRepository.test.ts +++ b/test/integration/collections/CollectionsRepository.test.ts @@ -17,7 +17,7 @@ import { restrictFile, deleteFile, linkDataset, - createTemplate, + createDatasetTemplate, MetadataFieldTypeClass } from '../../../src' import { ApiConfig } from '../../../src' @@ -2149,7 +2149,7 @@ describe('CollectionsRepository', () => { }) }) - describe('createTemplate', () => { + describe('createDatasetTemplate', () => { const templateDto: TemplateCreateDTO = { name: 'CollectionsRepository template', isDefault: true, @@ -2182,7 +2182,7 @@ describe('CollectionsRepository', () => { ] } test('should create a template in :root with provided JSON', async () => { - await createTemplate.execute(templateDto) + await createDatasetTemplate.execute(templateDto) const templates = await getDatasetTemplates.execute(':root') expect(templates[templates.length - 1].name).toBe(templateDto.name) @@ -2198,9 +2198,9 @@ describe('CollectionsRepository', () => { const expectedError = new WriteError( `[404] Can't find dataverse with identifier='invalidCollectionAlias'` ) - await expect(createTemplate.execute(templateDto, 'invalidCollectionAlias')).rejects.toThrow( - expectedError - ) + await expect( + createDatasetTemplate.execute(templateDto, 'invalidCollectionAlias') + ).rejects.toThrow(expectedError) }) }) }) diff --git a/test/unit/collections/CreateTemplate.test.ts b/test/unit/collections/createDatasetTemplate.ts similarity index 60% rename from test/unit/collections/CreateTemplate.test.ts rename to test/unit/collections/createDatasetTemplate.ts index 89c8d64b..6647bed6 100644 --- a/test/unit/collections/CreateTemplate.test.ts +++ b/test/unit/collections/createDatasetTemplate.ts @@ -1,4 +1,4 @@ -import { CreateTemplate } from '../../../src/collections/domain/useCases/CreateTemplate' +import { CreateDatasetTemplate } from '../../../src/collections/domain/useCases/CreateDatasetTemplate' import { ICollectionsRepository } from '../../../src/collections/domain/repositories/ICollectionsRepository' import { TemplateCreateDTO } from '../../../src/collections/domain/dtos/TemplateCreateDTO' import { WriteError } from '../../../src' @@ -9,23 +9,26 @@ describe('execute', () => { test('should return undefined when repository call is successful', async () => { const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository - collectionRepositoryStub.createTemplate = jest.fn().mockResolvedValue(testCollectionId) - const sut = new CreateTemplate(collectionRepositoryStub) + collectionRepositoryStub.createDatasetTemplate = jest.fn().mockResolvedValue(testCollectionId) + const sut = new CreateDatasetTemplate(collectionRepositoryStub) const actual = await sut.execute(testTemplateDTO) - expect(collectionRepositoryStub.createTemplate).toHaveBeenCalledWith(':root', testTemplateDTO) + expect(collectionRepositoryStub.createDatasetTemplate).toHaveBeenCalledWith( + ':root', + testTemplateDTO + ) expect(actual).toEqual(testCollectionId) }) test('should call repository with provided collection id/alias', async () => { const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository - collectionRepositoryStub.createTemplate = jest.fn().mockResolvedValue(testCollectionId) + collectionRepositoryStub.createDatasetTemplate = jest.fn().mockResolvedValue(testCollectionId) - const sut = new CreateTemplate(collectionRepositoryStub) + const sut = new CreateDatasetTemplate(collectionRepositoryStub) const actual = await sut.execute(testTemplateDTO, 'alias123') - expect(collectionRepositoryStub.createTemplate).toHaveBeenCalledWith( + expect(collectionRepositoryStub.createDatasetTemplate).toHaveBeenCalledWith( 'alias123', testTemplateDTO ) @@ -35,8 +38,8 @@ describe('execute', () => { test('should return error result on repository error', async () => { const collectionRepositoryStub: ICollectionsRepository = {} as ICollectionsRepository - collectionRepositoryStub.createTemplate = jest.fn().mockRejectedValue(new WriteError()) - const testCreateTemplate = new CreateTemplate(collectionRepositoryStub) + collectionRepositoryStub.createDatasetTemplate = jest.fn().mockRejectedValue(new WriteError()) + const testCreateTemplate = new CreateDatasetTemplate(collectionRepositoryStub) await expect(testCreateTemplate.execute(testTemplateDTO)).rejects.toThrow(WriteError) }) From a4206ddbda763868f2293e58b2a290bc1730cba5 Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Wed, 22 Oct 2025 17:05:26 -0400 Subject: [PATCH 3/4] chore: move the line in usecase.md --- docs/useCases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/useCases.md b/docs/useCases.md index d0dedb42..5ec382c6 100644 --- a/docs/useCases.md +++ b/docs/useCases.md @@ -18,7 +18,6 @@ The different use cases currently available in the package are classified below, - [Get Collection Featured Items](#get-collection-featured-items) - [Get Collections for Linking](#get-collections-for-linking) - [Collections write use cases](#collections-write-use-cases) - - [Create a Dataset Template](#create-a-dataset-template) - [Create a Collection](#create-a-collection) - [Update a Collection](#update-a-collection) - [Publish a Collection](#publish-a-collection) @@ -26,6 +25,7 @@ The different use cases currently available in the package are classified below, - [Update Collection Featured Items](#update-collection-featured-items) - [Delete Collection Featured Items](#delete-collection-featured-items) - [Delete a Collection Featured Item](#delete-a-collection-featured-item) + - [Create a Dataset Template](#create-a-dataset-template) - [Datasets](#Datasets) - [Datasets read use cases](#datasets-read-use-cases) - [Get a Dataset](#get-a-dataset) From 7c9a7cb368d56957800b6cfaf76bc60f5a1364f0 Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Wed, 22 Oct 2025 17:08:14 -0400 Subject: [PATCH 4/4] chore: renaming dto and revise changelog --- CHANGELOG.md | 2 +- .../{TemplateCreateDTO.ts => CreateDatasetTemplateDTO.ts} | 2 +- .../domain/repositories/ICollectionsRepository.ts | 4 ++-- src/collections/domain/useCases/CreateDatasetTemplate.ts | 6 +++--- src/collections/infra/repositories/CollectionsRepository.ts | 4 ++-- test/functional/collections/createDatasetTemplate.test.ts | 4 ++-- test/integration/collections/CollectionsRepository.test.ts | 4 ++-- test/unit/collections/createDatasetTemplate.ts | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) rename src/collections/domain/dtos/{TemplateCreateDTO.ts => CreateDatasetTemplateDTO.ts} (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md index c84c5d99..906a6918 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ This changelog follows the principles of [Keep a Changelog](https://keepachangel ### Added - New Use Case: [Get Collections For Linking Use Case](./docs/useCases.md#get-collections-for-linking). -- New Use Case: [Create a Template](./docs/useCases.md#create-a-template) under Collections. +- New Use Case: [Create a Dataset Template](./docs/useCases.md#create-a-dataset-template) under Collections. ### Changed diff --git a/src/collections/domain/dtos/TemplateCreateDTO.ts b/src/collections/domain/dtos/CreateDatasetTemplateDTO.ts similarity index 96% rename from src/collections/domain/dtos/TemplateCreateDTO.ts rename to src/collections/domain/dtos/CreateDatasetTemplateDTO.ts index a8b729b1..52ba24cc 100644 --- a/src/collections/domain/dtos/TemplateCreateDTO.ts +++ b/src/collections/domain/dtos/CreateDatasetTemplateDTO.ts @@ -1,6 +1,6 @@ import { MetadataFieldTypeClass } from '../../../metadataBlocks/domain/models/MetadataBlock' -export interface TemplateCreateDTO { +export interface CreateDatasetTemplateDTO { name: string isDefault?: boolean fields?: TemplateFieldDTO[] diff --git a/src/collections/domain/repositories/ICollectionsRepository.ts b/src/collections/domain/repositories/ICollectionsRepository.ts index 432749a0..cae28415 100644 --- a/src/collections/domain/repositories/ICollectionsRepository.ts +++ b/src/collections/domain/repositories/ICollectionsRepository.ts @@ -12,7 +12,7 @@ import { CollectionItemType } from '../../../collections/domain/models/Collectio import { CollectionLinks } from '../models/CollectionLinks' import { CollectionSummary } from '../models/CollectionSummary' import { LinkingObjectType } from '../useCases/GetCollectionsForLinking' -import { TemplateCreateDTO } from '../dtos/TemplateCreateDTO' +import { CreateDatasetTemplateDTO } from '../dtos/CreateDatasetTemplateDTO' export interface ICollectionsRepository { getCollection(collectionIdOrAlias: number | string): Promise @@ -71,6 +71,6 @@ export interface ICollectionsRepository { ): Promise createDatasetTemplate( collectionIdOrAlias: number | string, - template: TemplateCreateDTO + template: CreateDatasetTemplateDTO ): Promise } diff --git a/src/collections/domain/useCases/CreateDatasetTemplate.ts b/src/collections/domain/useCases/CreateDatasetTemplate.ts index 4236332d..ffb443f6 100644 --- a/src/collections/domain/useCases/CreateDatasetTemplate.ts +++ b/src/collections/domain/useCases/CreateDatasetTemplate.ts @@ -1,7 +1,7 @@ import { ROOT_COLLECTION_ID } from '../models/Collection' import { UseCase } from '../../../core/domain/useCases/UseCase' import { ICollectionsRepository } from '../repositories/ICollectionsRepository' -import { TemplateCreateDTO } from '../dtos/TemplateCreateDTO' +import { CreateDatasetTemplateDTO } from '../dtos/CreateDatasetTemplateDTO' export class CreateDatasetTemplate implements UseCase { private collectionsRepository: ICollectionsRepository @@ -13,13 +13,13 @@ export class CreateDatasetTemplate implements UseCase { /** * Creates a Dataset Template in the specified collection. * - * @param {TemplateCreateDTO} template - Template definition payload. + * @param {CreateDatasetTemplateDTO} template - Template definition payload. * @param {number | string} [collectionIdOrAlias = ':root'] - A generic collection identifier, which can be either a string (for queries by CollectionAlias), or a number (for queries by CollectionId) * If this parameter is not set, the default value is: ':root'. * @returns {Promise} */ async execute( - template: TemplateCreateDTO, + template: CreateDatasetTemplateDTO, collectionIdOrAlias: number | string = ROOT_COLLECTION_ID ): Promise { return await this.collectionsRepository.createDatasetTemplate(collectionIdOrAlias, template) diff --git a/src/collections/infra/repositories/CollectionsRepository.ts b/src/collections/infra/repositories/CollectionsRepository.ts index 62c8d936..53ebfff3 100644 --- a/src/collections/infra/repositories/CollectionsRepository.ts +++ b/src/collections/infra/repositories/CollectionsRepository.ts @@ -40,7 +40,7 @@ import { ReadError } from '../../../core/domain/repositories/ReadError' import { CollectionLinks } from '../../domain/models/CollectionLinks' import { CollectionSummary } from '../../domain/models/CollectionSummary' import { LinkingObjectType } from '../../domain/useCases/GetCollectionsForLinking' -import { TemplateCreateDTO } from '../../domain/dtos/TemplateCreateDTO' +import { CreateDatasetTemplateDTO } from '../../domain/dtos/CreateDatasetTemplateDTO' export interface NewCollectionRequestPayload { alias: string @@ -532,7 +532,7 @@ export class CollectionsRepository extends ApiRepository implements ICollections public async createDatasetTemplate( collectionIdOrAlias: number | string, - template: TemplateCreateDTO + template: CreateDatasetTemplateDTO ): Promise { return this.doPost( `/${this.collectionsResourceName}/${collectionIdOrAlias}/templates`, diff --git a/test/functional/collections/createDatasetTemplate.test.ts b/test/functional/collections/createDatasetTemplate.test.ts index bf89e319..84309e52 100644 --- a/test/functional/collections/createDatasetTemplate.test.ts +++ b/test/functional/collections/createDatasetTemplate.test.ts @@ -2,7 +2,7 @@ import { ApiConfig } from '../../../src' import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig' import { TestConstants } from '../../testHelpers/TestConstants' import { getDatasetTemplates } from '../../../src/datasets' -import { TemplateCreateDTO } from '../../../src/collections/domain/dtos/TemplateCreateDTO' +import { CreateDatasetTemplateDTO } from '../../../src/collections/domain/dtos/CreateDatasetTemplateDTO' import { createDatasetTemplate } from '../../../src/collections' import { MetadataFieldTypeClass } from '../../../src/metadataBlocks/domain/models/MetadataBlock' import { deleteDatasetTemplateViaApi } from '../../testHelpers/datasets/datasetTemplatesHelper' @@ -17,7 +17,7 @@ describe('CreateTemplate.execute', () => { }) test('should create a template in :root with provided JSON', async () => { - const templateDto: TemplateCreateDTO = { + const templateDto: CreateDatasetTemplateDTO = { name: 'TestDataverse template', isDefault: true, fields: [ diff --git a/test/integration/collections/CollectionsRepository.test.ts b/test/integration/collections/CollectionsRepository.test.ts index b82afca7..c5828eb2 100644 --- a/test/integration/collections/CollectionsRepository.test.ts +++ b/test/integration/collections/CollectionsRepository.test.ts @@ -60,7 +60,7 @@ import { DvObjectFeaturedItemDTO, FeaturedItemsDTO } from '../../../src/collections/domain/dtos/FeaturedItemsDTO' -import { TemplateCreateDTO } from '../../../src/collections/domain/dtos/TemplateCreateDTO' +import { CreateDatasetTemplateDTO } from '../../../src/collections/domain/dtos/CreateDatasetTemplateDTO' import { getDatasetTemplates } from '../../../src/datasets' import { deleteDatasetTemplateViaApi } from '../../testHelpers/datasets/datasetTemplatesHelper' @@ -2150,7 +2150,7 @@ describe('CollectionsRepository', () => { }) describe('createDatasetTemplate', () => { - const templateDto: TemplateCreateDTO = { + const templateDto: CreateDatasetTemplateDTO = { name: 'CollectionsRepository template', isDefault: true, fields: [ diff --git a/test/unit/collections/createDatasetTemplate.ts b/test/unit/collections/createDatasetTemplate.ts index 6647bed6..0004b7a7 100644 --- a/test/unit/collections/createDatasetTemplate.ts +++ b/test/unit/collections/createDatasetTemplate.ts @@ -1,10 +1,10 @@ import { CreateDatasetTemplate } from '../../../src/collections/domain/useCases/CreateDatasetTemplate' import { ICollectionsRepository } from '../../../src/collections/domain/repositories/ICollectionsRepository' -import { TemplateCreateDTO } from '../../../src/collections/domain/dtos/TemplateCreateDTO' +import { CreateDatasetTemplateDTO } from '../../../src/collections/domain/dtos/CreateDatasetTemplateDTO' import { WriteError } from '../../../src' describe('execute', () => { - const testTemplateDTO = { name: 't' } as TemplateCreateDTO + const testTemplateDTO = { name: 't' } as CreateDatasetTemplateDTO const testCollectionId = 1 test('should return undefined when repository call is successful', async () => {