Skip to content

Commit ad3f1cf

Browse files
committed
allow dataset to be created with non-default dataset type #359
1 parent fd1779c commit ad3f1cf

File tree

12 files changed

+261
-12
lines changed

12 files changed

+261
-12
lines changed

docs/useCases.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,7 @@ _See [use case](../src/datasets/domain/useCases/GetDatasetAvailableDatasetType.t
860860

861861
#### Create a Dataset
862862

863-
Creates a new Dataset in a collection, given a [DatasetDTO](../src/datasets/domain/dtos/DatasetDTO.ts) object and an optional collection identifier, which defaults to `:root`.
863+
Creates a new Dataset in a collection, given a [DatasetDTO](../src/datasets/domain/dtos/DatasetDTO.ts) object, an optional collection identifier, which defaults to `:root`, and an optional dataset type.
864864

865865
This use case validates the submitted fields of each metadata block and can return errors of type [ResourceValidationError](../src/core/domain/useCases/validators/errors/ResourceValidationError.ts), which include sufficient information to determine which field value is invalid and why.
866866

@@ -915,7 +915,7 @@ createDataset.execute(datasetDTO).then((newDatasetIds: CreatedDatasetIdentifiers
915915

916916
_See [use case](../src/datasets/domain/useCases/CreateDataset.ts) implementation_.
917917

918-
The above example creates the new dataset in the root collection since no collection identifier is specified. If you want to create the dataset in a different collection, you must add the collection identifier as a second parameter in the use case call.
918+
The above example creates the new dataset in the root collection since no collection identifier is specified. If you want to create the dataset in a different collection, you must add the collection identifier as a second parameter in the use case call. If you want the dataset type to be anything other than dataset, first [check available dataset types](#get-dataset-available-dataset-types) and then add the name of the dataset type as the third parameter.
919919

920920
The use case returns a [CreatedDatasetIdentifiers](../src/datasets/domain/models/CreatedDatasetIdentifiers.ts) object, which includes the persistent and numeric identifiers of the created dataset.
921921

src/datasets/domain/models/Dataset.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface Dataset {
1414
citationDate?: string
1515
metadataBlocks: DatasetMetadataBlocks
1616
isPartOf: DvObjectOwnerNode
17+
datasetType?: string
1718
}
1819

1920
export interface DatasetVersionInfo {

src/datasets/domain/repositories/IDatasetsRepository.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ export interface IDatasetsRepository {
4646
createDataset(
4747
newDataset: DatasetDTO,
4848
datasetMetadataBlocks: MetadataBlock[],
49-
collectionId: string
49+
collectionId: string,
50+
datasetType?: string
5051
): Promise<CreatedDatasetIdentifiers>
5152
publishDataset(datasetId: number | string, versionUpdateType: VersionUpdateType): Promise<void>
5253
updateDataset(

src/datasets/domain/useCases/CreateDataset.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,24 @@ export class CreateDataset extends DatasetWriteUseCase<CreatedDatasetIdentifiers
2020
*
2121
* @param {DatasetDTO} [newDataset] - DatasetDTO object including the new dataset metadata field values for each metadata block.
2222
* @param {string} [collectionId] - Specifies the collection identifier where the new dataset should be created (optional, defaults to :root).
23+
* @param {string} [datasetType] - Specifies the dataset type (optional, when omitted, defaults to "dataset").
2324
* @returns {Promise<CreatedDatasetIdentifiers>}
2425
* @throws {ResourceValidationError} - If there are validation errors related to the provided information.
2526
* @throws {ReadError} - If there are errors while reading data.
2627
* @throws {WriteError} - If there are errors while writing data.
2728
*/
2829
async execute(
2930
newDataset: DatasetDTO,
30-
collectionId = ROOT_COLLECTION_ID
31+
collectionId = ROOT_COLLECTION_ID,
32+
datasetType?: string
3133
): Promise<CreatedDatasetIdentifiers> {
3234
const metadataBlocks = await this.getNewDatasetMetadataBlocks(newDataset)
3335
this.getNewDatasetValidator().validate(newDataset, metadataBlocks)
34-
return this.getDatasetsRepository().createDataset(newDataset, metadataBlocks, collectionId)
36+
return this.getDatasetsRepository().createDataset(
37+
newDataset,
38+
metadataBlocks,
39+
collectionId,
40+
datasetType
41+
)
3542
}
3643
}

src/datasets/infra/repositories/DatasetsRepository.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,16 @@ export class DatasetsRepository extends ApiRepository implements IDatasetsReposi
208208
public async createDataset(
209209
newDataset: DatasetDTO,
210210
datasetMetadataBlocks: MetadataBlock[],
211-
collectionId: string
211+
collectionId: string,
212+
datasetType?: string
212213
): Promise<CreatedDatasetIdentifiers> {
213214
return this.doPost(
214215
`/dataverses/${collectionId}/datasets`,
215-
transformDatasetModelToNewDatasetRequestPayload(newDataset, datasetMetadataBlocks)
216+
transformDatasetModelToNewDatasetRequestPayload(
217+
newDataset,
218+
datasetMetadataBlocks,
219+
datasetType
220+
)
216221
)
217222
.then((response) => {
218223
const responseData = response.data.data

src/datasets/infra/repositories/transformers/DatasetPayload.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export interface DatasetPayload {
3636
files: FilePayload[]
3737
isPartOf: OwnerNodePayload
3838
deaccessionNote?: string
39+
datasetType?: string
3940
}
4041

4142
export interface DatasetLicensePayload {

src/datasets/infra/repositories/transformers/datasetTransformers.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { MetadataBlock, MetadataFieldInfo } from '../../../../metadataBlocks'
3131
const turndownService = new TurndownService()
3232

3333
export interface NewDatasetRequestPayload {
34+
datasetType?: string
3435
datasetVersion: {
3536
license?: DatasetLicense
3637
metadataBlocks: Record<string, MetadataBlockRequestPayload>
@@ -96,9 +97,11 @@ export const transformDatasetModelToUpdateDatasetRequestPayload = (
9697

9798
export const transformDatasetModelToNewDatasetRequestPayload = (
9899
dataset: DatasetDTO,
99-
metadataBlocks: MetadataBlock[]
100+
metadataBlocks: MetadataBlock[],
101+
datasetType?: string
100102
): NewDatasetRequestPayload => {
101103
return {
104+
datasetType,
102105
datasetVersion: {
103106
...(dataset.license && { license: dataset.license }),
104107
metadataBlocks: transformMetadataBlockModelsToRequestPayload(
@@ -293,6 +296,9 @@ export const transformVersionPayloadToDataset = (
293296
if ('citationDate' in versionPayload) {
294297
datasetModel.citationDate = versionPayload.citationDate
295298
}
299+
if ('datasetType' in versionPayload) {
300+
datasetModel.datasetType = versionPayload.datasetType
301+
}
296302
return datasetModel
297303
}
298304

test/functional/datasets/CreateDataset.test.ts

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createDataset, DatasetDTO } from '../../../src/datasets'
2-
import { ApiConfig } from '../../../src'
2+
import { ApiConfig, WriteError } from '../../../src'
33
import { TestConstants } from '../../testHelpers/TestConstants'
44
import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig'
55
import { FieldValidationError } from '../../../src/datasets/domain/useCases/validators/errors/FieldValidationError'
@@ -61,6 +61,58 @@ describe('execute', () => {
6161
}
6262
})
6363

64+
test('should successfully create a new dataset when a valid dataset type is sent', async () => {
65+
const testNewDataset = {
66+
metadataBlockValues: [
67+
{
68+
name: 'citation',
69+
fields: {
70+
title: 'Dataset created using the createDataset use case',
71+
author: [
72+
{
73+
authorName: 'Admin, Dataverse',
74+
authorAffiliation: 'Dataverse.org'
75+
},
76+
{
77+
authorName: 'Owner, Dataverse',
78+
authorAffiliation: 'Dataversedemo.org'
79+
}
80+
],
81+
datasetContact: [
82+
{
83+
datasetContactEmail: 'finch@mailinator.com',
84+
datasetContactName: 'Finch, Fiona'
85+
}
86+
],
87+
dsDescription: [
88+
{
89+
dsDescriptionValue: 'This is the description of the dataset.'
90+
}
91+
],
92+
subject: ['Medicine, Health and Life Sciences']
93+
}
94+
}
95+
]
96+
}
97+
expect.assertions(3)
98+
99+
try {
100+
const defaultDatasetType = 'dataset'
101+
const createdDatasetIdentifiers = await createDataset.execute(
102+
testNewDataset,
103+
':root',
104+
defaultDatasetType
105+
)
106+
107+
expect(createdDatasetIdentifiers).not.toBeNull()
108+
expect(createdDatasetIdentifiers.numericId).not.toBeNull()
109+
expect(createdDatasetIdentifiers.persistentId).not.toBeNull()
110+
await deleteUnpublishedDatasetViaApi(createdDatasetIdentifiers.numericId)
111+
} catch (error) {
112+
throw new Error('Dataset should be created')
113+
}
114+
})
115+
64116
test('should throw an error when a first level required field is missing', async () => {
65117
const testNewDataset = {
66118
metadataBlockValues: [
@@ -213,4 +265,52 @@ describe('execute', () => {
213265
)
214266
}
215267
})
268+
269+
test('should throw an error when an invalid dataset type is sent', async () => {
270+
const testNewDataset = {
271+
metadataBlockValues: [
272+
{
273+
name: 'citation',
274+
fields: {
275+
title: 'Dataset created using the createDataset use case',
276+
author: [
277+
{
278+
authorName: 'Admin, Dataverse',
279+
authorAffiliation: 'Dataverse.org'
280+
},
281+
{
282+
authorName: 'Owner, Dataverse',
283+
authorAffiliation: 'Dataversedemo.org'
284+
}
285+
],
286+
datasetContact: [
287+
{
288+
datasetContactEmail: 'finch@mailinator.com',
289+
datasetContactName: 'Finch, Fiona'
290+
}
291+
],
292+
dsDescription: [
293+
{
294+
dsDescriptionValue: 'This is the description of the dataset.'
295+
}
296+
],
297+
subject: ['Medicine, Health and Life Sciences']
298+
}
299+
}
300+
]
301+
}
302+
expect.assertions(1)
303+
let writeError: WriteError | undefined = undefined
304+
try {
305+
const invalidDatasetType = 'doesNotExist'
306+
await createDataset.execute(testNewDataset, ':root', invalidDatasetType)
307+
throw new Error('Use case should throw an error')
308+
} catch (error) {
309+
writeError = error as WriteError
310+
} finally {
311+
expect(writeError?.message).toEqual(
312+
'There was an error when writing the resource. Reason was: [400] Error parsing Json: Invalid dataset type: doesNotExist'
313+
)
314+
}
315+
})
216316
})

test/integration/datasets/DatasetsRepository.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ describe('DatasetsRepository', () => {
110110

111111
const filesRepositorySut = new FilesRepository()
112112
const directUploadSut: DirectUploadClient = new DirectUploadClient(filesRepositorySut)
113+
const defaultDatasetType = 'dataset'
113114

114115
beforeAll(async () => {
115116
ApiConfig.init(
@@ -827,6 +828,64 @@ describe('DatasetsRepository', () => {
827828
expect(actualCreatedDataset.metadataBlocks[0].fields.subject).toContain(
828829
'Medicine, Health and Life Sciences'
829830
)
831+
// even though we didn't provide a dataset type, it should be created with the default one
832+
expect(actualCreatedDataset.datasetType).toBe(defaultDatasetType)
833+
})
834+
})
835+
836+
describe('createDatasetWithDatasetType', () => {
837+
test('should create a dataset with the provided dataset type', async () => {
838+
const testNewDataset = {
839+
metadataBlockValues: [
840+
{
841+
name: 'citation',
842+
fields: {
843+
title: 'Dataset created using the createDataset use case',
844+
author: [
845+
{
846+
authorName: 'Admin, Dataverse',
847+
authorAffiliation: 'Dataverse.org'
848+
},
849+
{
850+
authorName: 'Owner, Dataverse',
851+
authorAffiliation: 'Dataversedemo.org'
852+
}
853+
],
854+
datasetContact: [
855+
{
856+
datasetContactEmail: 'finch@mailinator.com',
857+
datasetContactName: 'Finch, Fiona'
858+
}
859+
],
860+
dsDescription: [
861+
{
862+
dsDescriptionValue: 'This is the description of the dataset.'
863+
}
864+
],
865+
subject: ['Medicine, Health and Life Sciences']
866+
}
867+
}
868+
]
869+
}
870+
871+
const metadataBlocksRepository = new MetadataBlocksRepository()
872+
const citationMetadataBlock = await metadataBlocksRepository.getMetadataBlockByName(
873+
'citation'
874+
)
875+
const createdDataset = await sut.createDataset(
876+
testNewDataset,
877+
[citationMetadataBlock],
878+
ROOT_COLLECTION_ALIAS,
879+
defaultDatasetType
880+
)
881+
const actualCreatedDataset = await sut.getDataset(
882+
createdDataset.numericId,
883+
DatasetNotNumberedVersion.LATEST,
884+
false,
885+
false
886+
)
887+
888+
expect(actualCreatedDataset.datasetType).toBe(defaultDatasetType)
830889
})
831890
})
832891

test/testHelpers/datasets/datasetHelper.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,9 +694,11 @@ export const createDatasetMetadataBlockModel = (): MetadataBlock => {
694694
}
695695

696696
export const createNewDatasetRequestPayload = (
697-
license?: DatasetLicense
697+
license?: DatasetLicense,
698+
datasetType?: string
698699
): NewDatasetRequestPayload => {
699700
return {
701+
datasetType,
700702
datasetVersion: {
701703
...(license && { license }),
702704
metadataBlocks: {

0 commit comments

Comments
 (0)