Occurrent 0.4.0 is now available. The release contains several new features an upgrade to CloudEvent SDK 2.0.0.RC1. The SDK now contains a PojoCloudEventData type that makes DocumentCloudEventData, that was introduced in the previous release of Occurrent, superfluous. Another really important thing is that the cloud event extensions added automatically by Occurrent (for stream id and stream version) has been renamed from streamId and streamVersion to streamid and streamversion. This is because according to the cloud event specification, it’s not allowed to have attributes named with camelcase (must be lowercase).

Here are all changes:

  • Upgraded to Kotlin 1.4.20
  • Upgraded to cloud events 2.0.0.RC1
  • Breaking change! The attributes added by the Occurrent cloud event extension has been renamed from “streamId” and “streamVersion” to “streamid” and “streamversion” to comply with the specification.
  • Added optimized support for io.cloudevents.core.data.PojoCloudEventData. Occurrent can convert PojoCloudEventData that contains Map<String, Object> and String efficiently.
  • Breaking change! Removed org.occurrent.eventstore.mongodb.cloudevent.DocumentCloudEventData since it’s no longer needed after the CloudEvent SDK has introduced PojoCloudEventData. Use PojoCloudEventData and pass the document or preferably, map, to it.
  • Removed the org.occurrent:application-service-blocking-kotlin module, use org.occurrent:application-service-blocking instead. The Kotlin extension functions are provided with that module instead.
  • Added partial function application support for Kotlin. Depend on module org.occurrent:command-composition and import extension functions from org.occurrent.application.composition.command.partial. This means that instead of doing:

    val playerId = ...
    applicationService.execute(gameId) { events -> 
      Uno.play(events, Timestamp.now(), playerId, DigitCard(Three, Blue))
    }
    

    you can do:

    val playerId = ...
    applicationService.execute(gameId, Uno::play.partial(Timestamp.now(), playerId, DigitCard(Three, Blue))) 
    
  • Added command composition support for Kotlin. Depend on module org.occurrent:command-composition and import extension functions from org.occurrent.application.composition.command.*. This means that you can compose two functions like this using the andThen (infix) function:

      val numberOfPlayers = 4
      val timestamp = Timestamp.now()
      applicationService.execute(gameId, 
          Uno::start.partial(gameId, timestamp, numberOfPlayers) 
                  andThen Uno::play.partial(timestamp, player1, DigitCard(Three, Blue)))
    

    In the example above, start and play will be composed together into a single “command” that will be executed atomically.

    If you have more than two commands, it could be easier to use the composeCommand function instead of repeating andThen:

      val numberOfPlayers = 4
      val timestamp = Timestamp.now()
      applicationService.execute(gameId, 
          composeCommands(
              Uno::start.partial(gameId, timestamp, numberOfPlayers), 
              Uno::play.partial(timestamp, player1, DigitCard(Three, Blue)),
              Uno::play.partial(timestamp, player2, DigitCard(Four, Blue))
          )
      )
    
  • Added Kotlin extension functions to the blocking event store. They make it easier to write, read and query the event store with Kotlin Sequence’s. Import extension functions from package org.occurrent.eventstore.api.blocking.
  • Added support for deleting events from event store using a org.occurrent.filter.Filter. For example:

      eventStoreOperations.delete(streamId("myStream").and(streamVersion(lte(19L)));
    

    This will delete all events in stream “myStream” that has a version less than or equal to 19. This is useful if you implement “closing the books” or certain types of snapshots, and don’t need the old events anymore. This has been implemented for all MongoDB event stores (both blocking and reactive) but not for the InMemory event store.