spring-data-cosmosdb icon indicating copy to clipboard operation
spring-data-cosmosdb copied to clipboard

Support for the Unique Key for a Collection

Open jainro opened this issue 5 years ago • 6 comments

Adding Unique Key Constraints in Azure CosmosDB is supported now https://docs.microsoft.com/en-us/azure/cosmos-db/unique-keys

When will this be supported by the spring-data-cosmosdb?

jainro avatar May 09 '19 12:05 jainro

@mbhaskar Could you please help to share some information about this ?

Incarnation-p-lee avatar May 09 '19 14:05 Incarnation-p-lee

The unique key policy should be supported similar to how @DocumentIndexingPolicy works, by supplying an annotation on the document class.

allenhumphreys avatar Jun 22 '19 18:06 allenhumphreys

Thanks a lot, that should be something for serivce side configuration. We will add it to our feature list.

Incarnation-p-lee avatar Jun 23 '19 01:06 Incarnation-p-lee

As a workaround while waiting for first class support of this feature, I have come up with the following (in Kotlin):

Spring Bean Configuration Hooking

@Configuration
class CosmosUniqueKeyPolicyConfig(val documentDbConfiguration: AbstractDocumentDbConfiguration) {

    @Bean
    @Primary
    fun uniqueKeyPolicyHookingDocumentClient(): DocumentClient =
            uniqueKeyPolicyHookingDocumentDbFactory().getDocumentClient()

    @Bean
    @Primary
    fun uniqueKeyPolicyHookingDocumentDbFactory(): DocumentDbFactory =
            UniqueKeyPolicyHookingDocumentDbFactory(documentDbConfiguration.config)

    @Bean
    @Primary
    fun uniqueKeyPolicyHookingDocumentDbTemplate(): DocumentDbTemplate =
            DocumentDbTemplate(
                    this.uniqueKeyPolicyHookingDocumentDbFactory(),
                    documentDbConfiguration.mappingDocumentDbConverter(),
                    documentDbConfiguration.config.database)
}

class UniqueKeyPolicyHookingDocumentClient(
        serviceEndpoint: String?, 
        masterKey: String?, 
        connectionPolicy: ConnectionPolicy?, 
        desiredConsistencyLevel: ConsistencyLevel?
) : DocumentClient(serviceEndpoint, masterKey, connectionPolicy, desiredConsistencyLevel) {

    override fun createCollection(databaseLink: String?, collection: DocumentCollection?, options: RequestOptions?): ResourceResponse<DocumentCollection> {

        // Insert a unique key policy to the datamodel collection
        if (collection?.id == DocumentCollectionNames.datamodel) {
            collection.uniqueKeyPolicy = DataModel.uniqueKeyPolicy
        }

        return super.createCollection(databaseLink, collection, options)
    }
}

class UniqueKeyPolicyHookingDocumentDbFactory(config: DocumentDBConfig) : DocumentDbFactory(config) {
    
    override fun getDocumentClient(): DocumentClient {
        val config = config
        val policy = config.connectionPolicy
        val userAgent = "MyServer" + ";" + policy.userAgentSuffix

        policy.userAgentSuffix = userAgent

        return UniqueKeyPolicyHookingDocumentClient(config.uri, config.key, policy, config.consistencyLevel)
    }
}

object DocumentCollectionNames {
    const val datamodel = "datamodel_collection"
}

@Document(collection = DocumentCollectionNames.datamodel, ru = "400")
data class DataModel(
        @Id
        @GeneratedValue
        val id: String?,

        @PartitionKey
        val partitionKey: String,
        val uniqueKeyWithinPartition: String
) {
    companion object {
        val uniqueKeyPolicy: UniqueKeyPolicy by lazy {
            UniqueKeyPolicy().apply {
                uniqueKeys = listOf(UniqueKey().apply { paths = listOf("/uniqueKeyWithinPartition") })
            }
        }
    }
}

allenhumphreys avatar Jun 23 '19 14:06 allenhumphreys

@allenhumphreys Thanks for the suggestions.

@jainro - I will propose this feature for our next semester.

kushagraThapar avatar Jun 26 '20 19:06 kushagraThapar

Is there any progress here? I don't see anything in azure-spring-data-cosmos:3.5.0 and the workaround provided here is not adequate anymore

grzegorz-moto avatar Mar 19 '21 12:03 grzegorz-moto