Skip to content

Commit 98ee8bd

Browse files
committed
Merge remote-tracking branch 'origin/develop' into feature/configurable-uploads
# Conflicts: # CHANGELOG.md
2 parents cf1723f + a16321b commit 98ee8bd

26 files changed

Lines changed: 792 additions & 14 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ This changelog follows the principles of [Keep a Changelog](https://keepachangel
5353
- Templates: Rename `createDatasetTemplate` repository method to `createTemplate`.
5454
- Templates: Rename `getDatasetTemplates` repository method to `getTemplatesByCollectionId`.
5555
- Files: `DirectUploadClient` constructor now accepts a `DirectUploadClientConfig` object instead of a plain number for `maxMultipartRetries`.
56+
- 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.
5657

5758
### Fixed
5859

docs/useCases.md

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ The different use cases currently available in the package are classified below,
1111
- [Collections](#Collections)
1212
- [Collections read use cases](#collections-read-use-cases)
1313
- [Get a Collection](#get-a-collection)
14+
- [Get Collection Storage Driver](#get-collection-storage-driver)
15+
- [Get Allowed Collection Storage Drivers](#get-allowed-collection-storage-drivers)
1416
- [Get Collection Facets](#get-collection-facets)
1517
- [Get User Permissions on a Collection](#get-user-permissions-on-a-collection)
1618
- [List All Collection Items](#list-all-collection-items)
@@ -19,6 +21,8 @@ The different use cases currently available in the package are classified below,
1921
- [Get Collections for Linking](#get-collections-for-linking)
2022
- [Collections write use cases](#collections-write-use-cases)
2123
- [Create a Collection](#create-a-collection)
24+
- [Set Collection Storage Driver](#set-collection-storage-driver)
25+
- [Delete Collection Storage Driver](#delete-collection-storage-driver)
2226
- [Update a Collection](#update-a-collection)
2327
- [Publish a Collection](#publish-a-collection)
2428
- [Delete a Collection](#delete-a-collection)
@@ -192,6 +196,65 @@ The `collectionIdOrAlias` is a generic collection identifier, which can be eithe
192196

193197
If no collection identifier is specified, the default collection identifier; `:root` will be used. If you want to search for a different collection, you must add the collection identifier as a parameter in the use case call.
194198

199+
#### Get Collection Storage Driver
200+
201+
Returns a [StorageDriver](../src/core/domain/models/StorageDriver.ts) instance describing the collection's assigned storage driver.
202+
203+
##### Example call:
204+
205+
```typescript
206+
import { getCollectionStorageDriver } from '@iqss/dataverse-client-javascript'
207+
208+
/* ... */
209+
210+
const collectionIdOrAlias = 'classicLiterature'
211+
212+
getCollectionStorageDriver.execute(collectionIdOrAlias).then((storageDriver: StorageDriver) => {
213+
/* ... */
214+
})
215+
216+
// Pass true to resolve the effective driver after inheritance/default fallback
217+
getCollectionStorageDriver
218+
.execute(collectionIdOrAlias, true)
219+
.then((storageDriver: StorageDriver) => {
220+
/* ... */
221+
})
222+
223+
/* ... */
224+
```
225+
226+
_See [use case](../src/collections/domain/useCases/GetCollectionStorageDriver.ts) implementation_.
227+
228+
The `collectionIdOrAlias` is a generic collection identifier, which can be either a string (for queries by CollectionAlias), or a number (for queries by CollectionId).
229+
230+
The optional `getEffective` parameter defaults to `false`. Set it to `true` to retrieve the effective storage driver after inheritance/default resolution.
231+
232+
#### Get Allowed Collection Storage Drivers
233+
234+
Returns an [AllowedStorageDrivers](../src/collections/domain/models/AllowedStorageDrivers.ts) object whose keys are driver labels and whose values are storage driver ids.
235+
236+
##### Example call:
237+
238+
```typescript
239+
import { getAllowedCollectionStorageDrivers } from '@iqss/dataverse-client-javascript'
240+
241+
/* ... */
242+
243+
const collectionIdOrAlias = 'classicLiterature'
244+
245+
getAllowedCollectionStorageDrivers
246+
.execute(collectionIdOrAlias)
247+
.then((storageDrivers: AllowedStorageDrivers) => {
248+
/* ... */
249+
})
250+
251+
/* ... */
252+
```
253+
254+
_See [use case](../src/collections/domain/useCases/GetAllowedCollectionStorageDrivers.ts) implementation_.
255+
256+
The `collectionIdOrAlias` is a generic collection identifier, which can be either a string (for queries by CollectionAlias), or a number (for queries by CollectionId).
257+
195258
#### Get Collection Facets
196259

197260
Returns a [CollectionFacet](../src/collections/domain/models/CollectionFacet.ts) array containing the facets of the requested collection, given the collection identifier or alias.
@@ -462,6 +525,57 @@ The above example creates the new collection in the root collection since no col
462525

463526
The use case returns a number, which is the identifier of the created collection.
464527

528+
#### Set Collection Storage Driver
529+
530+
Assigns a storage driver to a collection by driver label and returns the backend success message.
531+
532+
##### Example call:
533+
534+
```typescript
535+
import { setCollectionStorageDriver } from '@iqss/dataverse-client-javascript'
536+
537+
/* ... */
538+
539+
const collectionIdOrAlias = 'classicLiterature'
540+
const driverLabel = 'Local Storage'
541+
542+
setCollectionStorageDriver.execute(collectionIdOrAlias, driverLabel).then((message: string) => {
543+
/* ... */
544+
})
545+
546+
/* ... */
547+
```
548+
549+
_See [use case](../src/collections/domain/useCases/SetCollectionStorageDriver.ts) implementation_.
550+
551+
The `collectionIdOrAlias` is a generic collection identifier, which can be either a string (for queries by CollectionAlias), or a number (for queries by CollectionId).
552+
553+
The `driverLabel` parameter must match the storage driver's label, not its id.
554+
555+
#### Delete Collection Storage Driver
556+
557+
Clears the directly assigned storage driver from a collection so it falls back to inherited/default storage, and returns the backend success message.
558+
559+
##### Example call:
560+
561+
```typescript
562+
import { deleteCollectionStorageDriver } from '@iqss/dataverse-client-javascript'
563+
564+
/* ... */
565+
566+
const collectionIdOrAlias = 'classicLiterature'
567+
568+
deleteCollectionStorageDriver.execute(collectionIdOrAlias).then((message: string) => {
569+
/* ... */
570+
})
571+
572+
/* ... */
573+
```
574+
575+
_See [use case](../src/collections/domain/useCases/DeleteCollectionStorageDriver.ts) implementation_.
576+
577+
The `collectionIdOrAlias` is a generic collection identifier, which can be either a string (for queries by CollectionAlias), or a number (for queries by CollectionId).
578+
465579
#### Update a Collection
466580

467581
Updates an existing collection, given a collection identifier and a [CollectionDTO](../src/collections/domain/dtos/CollectionDTO.ts) including the updated collection data.
@@ -1493,7 +1607,7 @@ _See [use case](../src/datasets/domain/useCases/GetDatasetTemplates.ts)_ definit
14931607

14941608
#### Get Dataset Storage Driver
14951609

1496-
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.
1610+
Returns a [StorageDriver](../src/core/domain/models/StorageDriver.ts) instance with storage driver configuration for a dataset, including properties like name, type, label, and upload/download capabilities.
14971611

14981612
##### Example call:
14991613

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type AllowedStorageDrivers = Record<string, string>

src/collections/domain/repositories/ICollectionsRepository.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,24 @@ import { PublicationStatus } from '../../../core/domain/models/PublicationStatus
1111
import { CollectionItemType } from '../../../collections/domain/models/CollectionItemType'
1212
import { CollectionLinks } from '../models/CollectionLinks'
1313
import { CollectionSummary } from '../models/CollectionSummary'
14+
import { AllowedStorageDrivers } from '../models/AllowedStorageDrivers'
15+
import { StorageDriver } from '../../../core/domain/models/StorageDriver'
1416
import { LinkingObjectType } from '../useCases/GetCollectionsForLinking'
1517

1618
export interface ICollectionsRepository {
1719
getCollection(collectionIdOrAlias: number | string): Promise<Collection>
20+
getCollectionStorageDriver(
21+
collectionIdOrAlias: number | string,
22+
getEffective?: boolean
23+
): Promise<StorageDriver>
24+
setCollectionStorageDriver(
25+
collectionIdOrAlias: number | string,
26+
driverLabel: string
27+
): Promise<string>
28+
deleteCollectionStorageDriver(collectionIdOrAlias: number | string): Promise<string>
29+
getAllowedCollectionStorageDrivers(
30+
collectionIdOrAlias: number | string
31+
): Promise<AllowedStorageDrivers>
1832
createCollection(
1933
collectionDTO: CollectionDTO,
2034
parentCollectionId: number | string
@@ -44,7 +58,7 @@ export interface ICollectionsRepository {
4458
): Promise<MyDataCollectionItemSubset>
4559
updateCollection(
4660
collectionIdOrAlias: number | string,
47-
updatedCollection: CollectionDTO
61+
updatedCollection: Partial<CollectionDTO>
4862
): Promise<void>
4963
getCollectionFeaturedItems(collectionIdOrAlias: number | string): Promise<FeaturedItem[]>
5064
updateCollectionFeaturedItems(
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { ICollectionsRepository } from '../repositories/ICollectionsRepository'
3+
4+
export class DeleteCollectionStorageDriver implements UseCase<string> {
5+
private collectionsRepository: ICollectionsRepository
6+
7+
constructor(collectionsRepository: ICollectionsRepository) {
8+
this.collectionsRepository = collectionsRepository
9+
}
10+
11+
async execute(collectionIdOrAlias: number | string): Promise<string> {
12+
return this.collectionsRepository.deleteCollectionStorageDriver(collectionIdOrAlias)
13+
}
14+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { ICollectionsRepository } from '../repositories/ICollectionsRepository'
3+
import { AllowedStorageDrivers } from '../models/AllowedStorageDrivers'
4+
5+
export class GetAllowedCollectionStorageDrivers implements UseCase<AllowedStorageDrivers> {
6+
private collectionsRepository: ICollectionsRepository
7+
8+
constructor(collectionsRepository: ICollectionsRepository) {
9+
this.collectionsRepository = collectionsRepository
10+
}
11+
12+
async execute(collectionIdOrAlias: number | string): Promise<AllowedStorageDrivers> {
13+
return this.collectionsRepository.getAllowedCollectionStorageDrivers(collectionIdOrAlias)
14+
}
15+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { StorageDriver } from '../../../core/domain/models/StorageDriver'
3+
import { ICollectionsRepository } from '../repositories/ICollectionsRepository'
4+
5+
export class GetCollectionStorageDriver implements UseCase<StorageDriver> {
6+
private collectionsRepository: ICollectionsRepository
7+
8+
constructor(collectionsRepository: ICollectionsRepository) {
9+
this.collectionsRepository = collectionsRepository
10+
}
11+
12+
async execute(
13+
collectionIdOrAlias: number | string,
14+
getEffective = false
15+
): Promise<StorageDriver> {
16+
return this.collectionsRepository.getCollectionStorageDriver(collectionIdOrAlias, getEffective)
17+
}
18+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { ICollectionsRepository } from '../repositories/ICollectionsRepository'
3+
4+
export class SetCollectionStorageDriver implements UseCase<string> {
5+
private collectionsRepository: ICollectionsRepository
6+
7+
constructor(collectionsRepository: ICollectionsRepository) {
8+
this.collectionsRepository = collectionsRepository
9+
}
10+
11+
async execute(collectionIdOrAlias: number | string, driverLabel: string): Promise<string> {
12+
return this.collectionsRepository.setCollectionStorageDriver(collectionIdOrAlias, driverLabel)
13+
}
14+
}

src/collections/domain/useCases/UpdateCollection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export class UpdateCollection implements UseCase<void> {
1919
*/
2020
async execute(
2121
collectionIdOrAlias: number | string,
22-
updatedCollection: CollectionDTO
22+
updatedCollection: Partial<CollectionDTO>
2323
): Promise<void> {
2424
return await this.collectionsRepository.updateCollection(collectionIdOrAlias, updatedCollection)
2525
}

src/collections/index.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { GetCollection } from './domain/useCases/GetCollection'
33
import { GetCollectionFacets } from './domain/useCases/GetCollectionFacets'
44
import { GetCollectionUserPermissions } from './domain/useCases/GetCollectionUserPermissions'
55
import { GetCollectionItems } from './domain/useCases/GetCollectionItems'
6+
import { GetCollectionStorageDriver } from './domain/useCases/GetCollectionStorageDriver'
67
import { PublishCollection } from './domain/useCases/PublishCollection'
78
import { UpdateCollection } from './domain/useCases/UpdateCollection'
89
import { GetCollectionFeaturedItems } from './domain/useCases/GetCollectionFeaturedItems'
@@ -16,10 +17,14 @@ import { LinkCollection } from './domain/useCases/LinkCollection'
1617
import { UnlinkCollection } from './domain/useCases/UnlinkCollection'
1718
import { GetCollectionLinks } from './domain/useCases/GetCollectionLinks'
1819
import { GetCollectionsForLinking } from './domain/useCases/GetCollectionsForLinking'
20+
import { SetCollectionStorageDriver } from './domain/useCases/SetCollectionStorageDriver'
21+
import { DeleteCollectionStorageDriver } from './domain/useCases/DeleteCollectionStorageDriver'
22+
import { GetAllowedCollectionStorageDrivers } from './domain/useCases/GetAllowedCollectionStorageDrivers'
1923

2024
const collectionsRepository = new CollectionsRepository()
2125

2226
const getCollection = new GetCollection(collectionsRepository)
27+
const getCollectionStorageDriver = new GetCollectionStorageDriver(collectionsRepository)
2328
const createCollection = new CreateCollection(collectionsRepository)
2429
const getCollectionFacets = new GetCollectionFacets(collectionsRepository)
2530
const getCollectionUserPermissions = new GetCollectionUserPermissions(collectionsRepository)
@@ -36,9 +41,15 @@ const linkCollection = new LinkCollection(collectionsRepository)
3641
const unlinkCollection = new UnlinkCollection(collectionsRepository)
3742
const getCollectionLinks = new GetCollectionLinks(collectionsRepository)
3843
const getCollectionsForLinking = new GetCollectionsForLinking(collectionsRepository)
44+
const setCollectionStorageDriver = new SetCollectionStorageDriver(collectionsRepository)
45+
const deleteCollectionStorageDriver = new DeleteCollectionStorageDriver(collectionsRepository)
46+
const getAllowedCollectionStorageDrivers = new GetAllowedCollectionStorageDrivers(
47+
collectionsRepository
48+
)
3949

4050
export {
4151
getCollection,
52+
getCollectionStorageDriver,
4253
createCollection,
4354
getCollectionFacets,
4455
getCollectionUserPermissions,
@@ -54,7 +65,10 @@ export {
5465
linkCollection,
5566
unlinkCollection,
5667
getCollectionLinks,
57-
getCollectionsForLinking
68+
getCollectionsForLinking,
69+
setCollectionStorageDriver,
70+
deleteCollectionStorageDriver,
71+
getAllowedCollectionStorageDrivers
5872
}
5973
export { Collection, CollectionInputLevel } from './domain/models/Collection'
6074
export { CollectionFacet } from './domain/models/CollectionFacet'
@@ -66,3 +80,4 @@ export { CollectionSearchCriteria } from './domain/models/CollectionSearchCriter
6680
export { FeaturedItem } from './domain/models/FeaturedItem'
6781
export { FeaturedItemsDTO } from './domain/dtos/FeaturedItemsDTO'
6882
export { CollectionSummary } from './domain/models/CollectionSummary'
83+
export { AllowedStorageDrivers } from './domain/models/AllowedStorageDrivers'

0 commit comments

Comments
 (0)