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 @@ -8,6 +8,7 @@ This changelog follows the principles of [Keep a Changelog](https://keepachangel

### Added

- Datasets: Added `getDatasetStorageDriver` use case and repository method to support Dataverse endpoint `GET /datasets/{identifier}/storageDriver`, for retrieving dataset storage driver configuration with properties: name, type, label, directUpload, directDownload, and uploadOutOfBand.
- Datasets: Added `updateDatasetLicense` use case and repository method to support Dataverse endpoint `PUT /datasets/{id}/license`, for updating dataset license or custom terms
- New Use Case: [Get Collections For Linking Use Case](./docs/useCases.md#get-collections-for-linking).
- New Use Case: [Create a Dataset Template](./docs/useCases.md#create-a-dataset-template) under Collections.
Expand Down
25 changes: 25 additions & 0 deletions docs/useCases.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ The different use cases currently available in the package are classified below,
- [Get Dataset Linked Collections](#get-dataset-linked-collections)
- [Get Dataset Available Categories](#get-dataset-available-categories)
- [Get Dataset Templates](#get-dataset-templates)
- [Get Dataset Storage Driver](#get-dataset-storage-driver)
- [Get Dataset Available Dataset Types](#get-dataset-available-dataset-types)
- [Get Dataset Available Dataset Type](#get-dataset-available-dataset-type)
- [Datasets write use cases](#datasets-write-use-cases)
Expand Down Expand Up @@ -1351,6 +1352,30 @@ getDatasetTemplates.execute(collectionIdOrAlias).then((datasetTemplates: Dataset

_See [use case](../src/datasets/domain/useCases/GetDatasetTemplates.ts)_ definition.

#### Get Dataset Storage Driver

Returns a [StorageDriver](../src/datasets/domain/models/StorageDriver.ts) instance with storage driver configuration for a dataset, including properties like name, type, label, and upload/download capabilities.

##### Example call:

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

/* ... */

const datasetId = 'doi:10.77777/FK2/AAAAAA'

getDatasetStorageDriver.execute(datasetId).then((storageDriver: StorageDriver) => {
/* ... */
})

/* ... */
```

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

The `datasetId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers.

#### Add a Dataset Type

Adds a dataset types that can be used at dataset creation.
Expand Down
8 changes: 8 additions & 0 deletions src/datasets/domain/models/StorageDriver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface StorageDriver {
name: string
type: string
label: string
directUpload: boolean
directDownload: boolean
uploadOutOfBand: boolean
}
2 changes: 2 additions & 0 deletions src/datasets/domain/repositories/IDatasetsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { DatasetType } from '../models/DatasetType'
import { TermsOfAccess } from '../models/Dataset'
import { DatasetLicenseUpdateRequest } from '../dtos/DatasetLicenseUpdateRequest'
import { DatasetTypeDTO } from '../dtos/DatasetTypeDTO'
import { StorageDriver } from '../models/StorageDriver'

export interface IDatasetsRepository {
getDataset(
Expand Down Expand Up @@ -102,4 +103,5 @@ export interface IDatasetsRepository {
datasetId: number | string,
payload: DatasetLicenseUpdateRequest
): Promise<void>
getDatasetStorageDriver(datasetId: number | string): Promise<StorageDriver>
}
21 changes: 21 additions & 0 deletions src/datasets/domain/useCases/GetDatasetStorageDriver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { UseCase } from '../../../core/domain/useCases/UseCase'
import { IDatasetsRepository } from '../repositories/IDatasetsRepository'
import { StorageDriver } from '../models/StorageDriver'

export class GetDatasetStorageDriver implements UseCase<StorageDriver> {
private datasetsRepository: IDatasetsRepository

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

/**
* Returns the storage driver information for a given Dataset.
*
* @param {number | string} [datasetId] - The dataset identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers).
* @returns {Promise<StorageDriver>}
*/
async execute(datasetId: number | string): Promise<StorageDriver> {
return this.datasetsRepository.getDatasetStorageDriver(datasetId)
}
}
6 changes: 5 additions & 1 deletion src/datasets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { GetDatasetCitationInOtherFormats } from './domain/useCases/GetDatasetCi
import { GetDatasetTemplates } from './domain/useCases/GetDatasetTemplates'
import { UpdateTermsOfAccess } from './domain/useCases/UpdateTermsOfAccess'
import { UpdateDatasetLicense } from './domain/useCases/UpdateDatasetLicense'
import { GetDatasetStorageDriver } from './domain/useCases/GetDatasetStorageDriver'

const datasetsRepository = new DatasetsRepository()

Expand Down Expand Up @@ -84,6 +85,7 @@ const getDatasetCitationInOtherFormats = new GetDatasetCitationInOtherFormats(da
const getDatasetTemplates = new GetDatasetTemplates(datasetsRepository)
const updateTermsOfAccess = new UpdateTermsOfAccess(datasetsRepository)
const updateDatasetLicense = new UpdateDatasetLicense(datasetsRepository)
const getDatasetStorageDriver = new GetDatasetStorageDriver(datasetsRepository)

export {
getDataset,
Expand Down Expand Up @@ -115,7 +117,8 @@ export {
linkDatasetTypeWithMetadataBlocks,
setAvailableLicensesForDatasetType,
deleteDatasetType,
updateDatasetLicense
updateDatasetLicense,
getDatasetStorageDriver
}
export { DatasetNotNumberedVersion } from './domain/models/DatasetNotNumberedVersion'
export { DatasetUserPermissions } from './domain/models/DatasetUserPermissions'
Expand Down Expand Up @@ -154,3 +157,4 @@ export {
export { DatasetLinkedCollection } from './domain/models/DatasetLinkedCollection'
export { DatasetType } from './domain/models/DatasetType'
export { DatasetTypeDTO } from './domain/dtos/DatasetTypeDTO'
export { StorageDriver } from './domain/models/StorageDriver'
12 changes: 12 additions & 0 deletions src/datasets/infra/repositories/DatasetsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { TermsOfAccess } from '../../domain/models/Dataset'
import { transformTermsOfAccessToUpdatePayload } from './transformers/termsOfAccessTransformers'
import { DatasetLicenseUpdateRequest } from '../../domain/dtos/DatasetLicenseUpdateRequest'
import { DatasetTypeDTO } from '../../domain/dtos/DatasetTypeDTO'
import { StorageDriver } from '../../domain/models/StorageDriver'

export interface GetAllDatasetPreviewsQueryParams {
per_page?: number
Expand Down Expand Up @@ -515,4 +516,15 @@ export class DatasetsRepository extends ApiRepository implements IDatasetsReposi
throw error
})
}

public async getDatasetStorageDriver(datasetId: number | string): Promise<StorageDriver> {
return this.doGet(
this.buildApiEndpoint(this.datasetsResourceName, 'storageDriver', datasetId),
true
)
.then((response) => response.data.data as StorageDriver)
.catch((error) => {
throw error
})
}
}
24 changes: 24 additions & 0 deletions test/integration/datasets/DatasetsRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2244,4 +2244,28 @@ describe('DatasetsRepository', () => {
await deleteUnpublishedDatasetViaApi(testDatasetIds.numericId)
})
})

describe('getDatasetStorageDriver', () => {
let testDatasetIds: CreatedDatasetIdentifiers

beforeAll(async () => {
testDatasetIds = await createDataset.execute(TestConstants.TEST_NEW_DATASET_DTO)
await publishDatasetViaApi(testDatasetIds.numericId)
await waitForNoLocks(testDatasetIds.numericId, 10)
})

afterAll(async () => {
await deletePublishedDatasetViaApi(testDatasetIds.persistentId)
})

test('should return storage driver info for dataset', async () => {
const storageDriver = await sut.getDatasetStorageDriver(testDatasetIds.numericId)
expect(storageDriver).toHaveProperty('name')
expect(storageDriver).toHaveProperty('type')
expect(storageDriver).toHaveProperty('label')
expect(typeof storageDriver.directUpload).toBe('boolean')
expect(typeof storageDriver.directDownload).toBe('boolean')
expect(typeof storageDriver.uploadOutOfBand).toBe('boolean')
})
})
})
51 changes: 51 additions & 0 deletions test/unit/datasets/GetDatasetStorageDriver.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { GetDatasetStorageDriver } from '../../../src/datasets/domain/useCases/GetDatasetStorageDriver'
import { IDatasetsRepository } from '../../../src/datasets/domain/repositories/IDatasetsRepository'
import { StorageDriver } from '../../../src/datasets/domain/models/StorageDriver'
import { ReadError } from '../../../src/core/domain/repositories/ReadError'

describe('GetDatasetStorageDriver (unit)', () => {
const testStorageDriver: StorageDriver = {
name: 'local',
type: 'filesystem',
label: 'Local Storage',
directUpload: true,
directDownload: true,
uploadOutOfBand: false
}

test('should return storage driver on repository success', async () => {
const datasetsRepositoryStub: IDatasetsRepository = {} as IDatasetsRepository
datasetsRepositoryStub.getDatasetStorageDriver = jest.fn().mockResolvedValue(testStorageDriver)
const sut = new GetDatasetStorageDriver(datasetsRepositoryStub)

const actual = await sut.execute(1)

expect(actual).toEqual(testStorageDriver)
expect(actual.name).toBe('local')
expect(actual.type).toBe('filesystem')
expect(actual.label).toBe('Local Storage')
expect(actual.directUpload).toBe(true)
expect(actual.directDownload).toBe(true)
expect(actual.uploadOutOfBand).toBe(false)
})

test('should return storage driver when using persistent id', async () => {
const datasetsRepositoryStub: IDatasetsRepository = {} as IDatasetsRepository
datasetsRepositoryStub.getDatasetStorageDriver = jest.fn().mockResolvedValue(testStorageDriver)
const sut = new GetDatasetStorageDriver(datasetsRepositoryStub)

const actual = await sut.execute('doi:10.77777/FK2/AAAAAA')

expect(actual).toEqual(testStorageDriver)
})

test('should return error result on repository error', async () => {
const datasetsRepositoryStub: IDatasetsRepository = {} as IDatasetsRepository
datasetsRepositoryStub.getDatasetStorageDriver = jest
.fn()
.mockRejectedValue(new ReadError('[404] Dataset not found'))
const sut = new GetDatasetStorageDriver(datasetsRepositoryStub)

await expect(sut.execute(1)).rejects.toThrow(ReadError)
})
})