Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This changelog follows the principles of [Keep a Changelog](https://keepachangel
- Templates: Rename `CreateDatasetTemplateDTO` to `CreateTemplateDTO`.
- Templates: Rename `createDatasetTemplate` repository method to `createTemplate`.
- Templates: Rename `getDatasetTemplates` repository method to `getTemplatesByCollectionId`.
- Collections: `updateCollection` now supports partial updates by accepting `Partial<CollectionDTO>`. Only explicitly provided fields are sent in update requests, aligning with Dataverse API semantics. Metadata blocks handling was adjusted to respect inheritance flags and avoid invalid field combinations.

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export interface ICollectionsRepository {
): Promise<MyDataCollectionItemSubset>
updateCollection(
collectionIdOrAlias: number | string,
updatedCollection: CollectionDTO
updatedCollection: Partial<CollectionDTO>
): Promise<void>
getCollectionFeaturedItems(collectionIdOrAlias: number | string): Promise<FeaturedItem[]>
updateCollectionFeaturedItems(
Expand Down
2 changes: 1 addition & 1 deletion src/collections/domain/useCases/UpdateCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class UpdateCollection implements UseCase<void> {
*/
async execute(
collectionIdOrAlias: number | string,
updatedCollection: CollectionDTO
updatedCollection: Partial<CollectionDTO>
): Promise<void> {
return await this.collectionsRepository.updateCollection(collectionIdOrAlias, updatedCollection)
}
Expand Down
84 changes: 82 additions & 2 deletions src/collections/infra/repositories/CollectionsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,9 @@ export class CollectionsRepository extends ApiRepository implements ICollections

public async updateCollection(
collectionIdOrAlias: string | number,
updatedCollection: CollectionDTO
updatedCollection: Partial<CollectionDTO>
): Promise<void> {
const requestBody = this.createCreateOrUpdateRequestBody(updatedCollection)
const requestBody = this.createUpdateRequestBody(updatedCollection)

return this.doPut(`/${this.collectionsResourceName}/${collectionIdOrAlias}`, requestBody)
.then(() => undefined)
Expand Down Expand Up @@ -332,6 +332,86 @@ export class CollectionsRepository extends ApiRepository implements ICollections
}
}

private createUpdateRequestBody(
collectionDTO: Partial<CollectionDTO>
): Partial<NewCollectionRequestPayload> {
const dataverseContacts: NewCollectionContactRequestPayload[] | undefined =
collectionDTO.contacts?.map((contact) => ({
contactEmail: contact
}))
const inputLevelsRequestBody: NewCollectionInputLevelRequestPayload[] | undefined =
collectionDTO.inputLevels?.map((inputLevel) => ({
datasetFieldTypeName: inputLevel.datasetFieldName,
include: inputLevel.include,
required: inputLevel.required
}))
let metadataBlocksRequestBody: Partial<NewCollectionMetadataBlocksRequestPayload> | undefined

const hasMetadataBlocksData =
collectionDTO.metadataBlockNames !== undefined ||
collectionDTO.facetIds !== undefined ||
collectionDTO.inputLevels !== undefined ||
collectionDTO.inheritMetadataBlocksFromParent !== undefined ||
collectionDTO.inheritFacetsFromParent !== undefined

if (hasMetadataBlocksData) {
metadataBlocksRequestBody = {}
if (collectionDTO.inheritMetadataBlocksFromParent !== true) {
if (collectionDTO.metadataBlockNames !== undefined) {
metadataBlocksRequestBody.metadataBlockNames = collectionDTO.metadataBlockNames
}
if (inputLevelsRequestBody !== undefined) {
metadataBlocksRequestBody.inputLevels = inputLevelsRequestBody
}
}
if (collectionDTO.inheritFacetsFromParent !== true) {
if (collectionDTO.facetIds !== undefined) {
metadataBlocksRequestBody.facetIds = collectionDTO.facetIds
}
}
if (collectionDTO.inheritMetadataBlocksFromParent !== undefined) {
metadataBlocksRequestBody.inheritMetadataBlocksFromParent =
collectionDTO.inheritMetadataBlocksFromParent
}
if (collectionDTO.inheritFacetsFromParent !== undefined) {
metadataBlocksRequestBody.inheritFacetsFromParent = collectionDTO.inheritFacetsFromParent
}
}

// Build the final request body, only including defined fields
const requestBody: Partial<NewCollectionRequestPayload> = {}

if (collectionDTO.alias !== undefined) {
requestBody.alias = collectionDTO.alias
}

if (collectionDTO.name !== undefined) {
requestBody.name = collectionDTO.name
}

if (dataverseContacts !== undefined) {
requestBody.dataverseContacts = dataverseContacts
}

if (collectionDTO.type !== undefined) {
requestBody.dataverseType = collectionDTO.type
}

if (collectionDTO.description !== undefined) {
requestBody.description = collectionDTO.description
}

if (collectionDTO.affiliation !== undefined) {
requestBody.affiliation = collectionDTO.affiliation
}

if (metadataBlocksRequestBody !== undefined) {
requestBody.metadataBlocks = metadataBlocksRequestBody
}

return requestBody
}

private applyCollectionSearchCriteriaToQueryParams(
queryParams: URLSearchParams,
collectionSearchCriteria: CollectionSearchCriteria
Expand Down
25 changes: 24 additions & 1 deletion test/functional/collections/UpdateCollection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {
WriteError,
createCollection,
getCollection,
updateCollection
updateCollection,
CollectionDTO
} from '../../../src'
import { TestConstants } from '../../testHelpers/TestConstants'
import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig'
Expand Down Expand Up @@ -35,6 +36,28 @@ describe('execute', () => {
}
})

test('should successfully update a collection with partial data (name only)', async () => {
const testNewCollectionAlias = 'updateCollection-partial-test'
const testNewCollection = createCollectionDTO(testNewCollectionAlias)
await createCollection.execute(testNewCollection)

const partialUpdate: Partial<CollectionDTO> = {
name: 'Partially Updated Name'
}

expect.assertions(3)
try {
await updateCollection.execute(testNewCollectionAlias, partialUpdate)
} catch (error) {
throw new Error('Collection should be updated with partial data')
} finally {
const updatedCollection = await getCollection.execute(testNewCollectionAlias)
expect(updatedCollection.name).toBe('Partially Updated Name')
expect(updatedCollection.alias).toBe(testNewCollectionAlias)
expect(updatedCollection.type).toBe(testNewCollection.type)
}
})

test('should throw an error when the parent collection does not exist', async () => {
const testNewCollection = createCollectionDTO()
expect.assertions(2)
Expand Down
21 changes: 21 additions & 0 deletions test/integration/collections/CollectionsRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,27 @@ describe('CollectionsRepository', () => {
expect(updatedInputLevel?.required).toBe(false)
})

test('should update collection with only partial fields (name and affiliation)', async () => {
const collectionDTO = createCollectionDTO('partial-update-test')
const testCollectionId = await sut.createCollection(collectionDTO)
const createdCollection = await sut.getCollection(testCollectionId)
const partialUpdate: Partial<CollectionDTO> = {
name: 'Partially Updated Name',
affiliation: 'New Affiliation'
}

await sut.updateCollection(testCollectionId, partialUpdate)
const updatedCollection = await sut.getCollection(testCollectionId)

expect(updatedCollection.name).toBe('Partially Updated Name')
expect(updatedCollection.affiliation).toBe('New Affiliation')
expect(updatedCollection.alias).toBe(createdCollection.alias)
expect(updatedCollection.type).toBe(createdCollection.type)
expect(updatedCollection.contacts).toEqual(createdCollection.contacts)

await deleteCollectionViaApi(collectionDTO.alias)
})

test('should update the collection to inherit metadata blocks from parent collection', async () => {
const parentCollectionAlias = 'inherit-metablocks-parent-update'
const parentCollectionDTO = createCollectionDTO(parentCollectionAlias)
Expand Down