Skip to content
Merged
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
25 changes: 25 additions & 0 deletions docs/useCases.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The different use cases currently available in the package are classified below,
- [Update a Dataset](#update-a-dataset)
- [Publish a Dataset](#publish-a-dataset)
- [Deaccession a Dataset](#deaccession-a-dataset)
- [Delete a Draft Dataset](#delete-a-draft-dataset)
- [Files](#Files)
- [Files read use cases](#files-read-use-cases)
- [Get a File](#get-a-file)
Expand Down Expand Up @@ -837,6 +838,30 @@ The `version` parameter should be a string or a [DatasetNotNumberedVersion](../s

You cannot deaccession a dataset more than once. If you call this endpoint twice for the same dataset version, you will get a not found error on the second call, since the dataset you are looking for will no longer be published since it is already deaccessioned.

#### Delete a Draft Dataset

Delete a Draft Dataset, given its identifier.

##### Example call:

```typescript
import { deleteDatasetDraft } from '@iqss/dataverse-client-javascript'

/* ... */

const datasetId = 1

deleteDatasetDraft.execute(datasetId)

/* ... */
```

_See [use case](../src/datasets/domain/useCases/DeleteDatasetDraft.ts) implementation_.

The `datasetId` parameter is a number for numeric identifiers or string for persistent identifiers.

If you try to delete a dataset without draft version, you will get a not found error.

#### Get Download Count of a Dataset

Total number of downloads requested for a dataset, given a dataset numeric identifier,
Expand Down
1 change: 1 addition & 0 deletions src/datasets/domain/repositories/IDatasetsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,5 @@ export interface IDatasetsRepository {
includeMDC?: boolean
): Promise<DatasetDownloadCount>
getDatasetVersionsSummaries(datasetId: number | string): Promise<DatasetVersionSummaryInfo[]>
deleteDatasetDraft(datasetId: number | string): Promise<void>
}
19 changes: 19 additions & 0 deletions src/datasets/domain/useCases/DeleteDatasetDraft.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { UseCase } from '../../../core/domain/useCases/UseCase'
import { IDatasetsRepository } from '../repositories/IDatasetsRepository'

export class DeleteDatasetDraft implements UseCase<void> {
private datasetsRepository: IDatasetsRepository

constructor(datasetsRepository: IDatasetsRepository) {
this.datasetsRepository = datasetsRepository
}

/**
* Delete a Draft Dataset
*
* @param {number | string} [datasetId] - The dataset identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers).
*/
async execute(datasetId: number | string): Promise<void> {
return this.datasetsRepository.deleteDatasetDraft(datasetId)
}
}
5 changes: 4 additions & 1 deletion src/datasets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { GetDatasetVersionDiff } from './domain/useCases/GetDatasetVersionDiff'
import { DeaccessionDataset } from './domain/useCases/DeaccessionDataset'
import { GetDatasetDownloadCount } from './domain/useCases/GetDatasetDownloadCount'
import { GetDatasetVersionsSummaries } from './domain/useCases/GetDatasetVersionsSummaries'
import { DeleteDatasetDraft } from './domain/useCases/DeleteDatasetDraft'

const datasetsRepository = new DatasetsRepository()

Expand Down Expand Up @@ -52,6 +53,7 @@ const updateDataset = new UpdateDataset(
const deaccessionDataset = new DeaccessionDataset(datasetsRepository)
const getDatasetDownloadCount = new GetDatasetDownloadCount(datasetsRepository)
const getDatasetVersionsSummaries = new GetDatasetVersionsSummaries(datasetsRepository)
const deleteDatasetDraft = new DeleteDatasetDraft(datasetsRepository)

export {
getDataset,
Expand All @@ -68,7 +70,8 @@ export {
updateDataset,
deaccessionDataset,
getDatasetDownloadCount,
getDatasetVersionsSummaries
getDatasetVersionsSummaries,
deleteDatasetDraft
}
export { DatasetNotNumberedVersion } from './domain/models/DatasetNotNumberedVersion'
export { DatasetUserPermissions } from './domain/models/DatasetUserPermissions'
Expand Down
10 changes: 10 additions & 0 deletions src/datasets/infra/repositories/DatasetsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,4 +277,14 @@ export class DatasetsRepository extends ApiRepository implements IDatasetsReposi
throw error
})
}

public async deleteDatasetDraft(datasetId: string | number): Promise<void> {
return this.doDelete(
this.buildApiEndpoint(this.datasetsResourceName, 'versions/:draft', datasetId)
)
.then(() => undefined)
.catch((error) => {
throw error
})
}
}
64 changes: 64 additions & 0 deletions test/functional/datasets/DeleteDatasetDraft.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { createDataset, deleteDatasetDraft } from '../../../src/datasets'
import { ApiConfig, WriteError } from '../../../src'
import { TestConstants } from '../../testHelpers/TestConstants'
import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig'

const testDataset = {
license: {
name: 'CC0 1.0',
uri: 'http://creativecommons.org/publicdomain/zero/1.0',
iconUri: 'https://licensebuttons.net/p/zero/1.0/88x31.png'
},
metadataBlockValues: [
{
name: 'citation',
fields: {
title: 'Dataset created using the createDataset use case',
author: [
{
authorName: 'Admin, Dataverse',
authorAffiliation: 'Dataverse.org'
},
{
authorName: 'Owner, Dataverse',
authorAffiliation: 'Dataversedemo.org'
}
],
datasetContact: [
{
datasetContactEmail: '[email protected]',
datasetContactName: 'Finch, Fiona'
}
],
dsDescription: [
{
dsDescriptionValue: 'This is the description of the dataset.'
}
],
subject: ['Medicine, Health and Life Sciences']
}
}
]
}

describe('execute', () => {
beforeEach(async () => {
ApiConfig.init(
TestConstants.TEST_API_URL,
DataverseApiAuthMechanism.API_KEY,
process.env.TEST_API_KEY
)
})

test('should delete a dataset when it is draft successfully', async () => {
const createdDatasetIdentifiers = await createDataset.execute(testDataset)

const actual = await deleteDatasetDraft.execute(createdDatasetIdentifiers.numericId)

expect(actual).toBeUndefined()
})

test('should throw an error when the dataset id is incorrect', async () => {
await expect(deleteDatasetDraft.execute(1111)).rejects.toBeInstanceOf(WriteError)
})
})
28 changes: 28 additions & 0 deletions test/integration/datasets/DatasetsRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1336,4 +1336,32 @@ describe('DatasetsRepository', () => {
)
})
})

describe('deleteDatasetDraft', () => {
test('should delete a draft dataset', async () => {
const testDatasetIds = await createDataset.execute(TestConstants.TEST_NEW_DATASET_DTO)

await waitForNoLocks(testDatasetIds.numericId, 10)

const actual = await sut.deleteDatasetDraft(testDatasetIds.numericId)

expect(actual).toBeUndefined()

const expectedError = new ReadError(
`[404] Dataset with ID ${testDatasetIds.numericId} not found.`
)

await expect(
sut.getDataset(testDatasetIds.numericId, DatasetNotNumberedVersion.LATEST, false, false)
).rejects.toThrow(expectedError)
})

test('should return error when dataset does not exist', async () => {
const expectedError = new WriteError(
`[404] Dataset with ID ${nonExistentTestDatasetId} not found.`
)

await expect(sut.deleteDatasetDraft(nonExistentTestDatasetId)).rejects.toThrow(expectedError)
})
})
})
23 changes: 23 additions & 0 deletions test/unit/datasets/DeleteDatasetDraft.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { DeleteDatasetDraft } from '../../../src/datasets/domain/useCases/DeleteDatasetDraft'
import { IDatasetsRepository } from '../../../src/datasets/domain/repositories/IDatasetsRepository'
import { WriteError } from '../../../src'

describe('execute', () => {
test('should return undefined on delete success', async () => {
const datasetsRepositoryStub: IDatasetsRepository = {} as IDatasetsRepository
datasetsRepositoryStub.deleteDatasetDraft = jest.fn().mockResolvedValue(undefined)
const sut = new DeleteDatasetDraft(datasetsRepositoryStub)

const actual = await sut.execute(1)
expect(actual).toEqual(undefined)
})

test('should return error result on delete error', async () => {
const datasetsRepositoryStub: IDatasetsRepository = {} as IDatasetsRepository
datasetsRepositoryStub.deleteDatasetDraft = jest.fn().mockRejectedValue(new WriteError())
const sut = new DeleteDatasetDraft(datasetsRepositoryStub)

const nonExistentDatasetId = 111
await expect(sut.execute(nonExistentDatasetId)).rejects.toThrow(WriteError)
})
})