Dzoukr / CosmoStore

F# Event store for Azure Cosmos DB, Table Storage, Postgres, LiteDB & ServiceStack

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Need some details for contribution

kunjee17 opened this issue · comments

Hi @Dzoukr

It would be great if you can provide some details around the contribution. I ll start with few questions.

  • What is getting store? From the code I figure it out that Stream type and EventRead is getting stored. But I am not sure if anything I missed.
  • When we are creating EventRead createdUtc is based on event or stream's createUtc.
  • Is any validation I need to take care of ? I got one validation about expected position but is there any other validation is there?
  • Is there any coding guideline for adding support of another data store ?

Hi @kunjee17,
thanks for creating new storage provider for CosmoStore!

To your questions:

When we are creating EventRead createdUtc is based on event or stream's createUtc.

CreatedUtc value is created when stored EventWrite. The value for Stream metadata can differ (only in miliseconds, most likely), because it is meant to be timestamp of metadata stored, but that is ok. In other words - CreatedUtc on EventRead and CreatedUtc on Metadata can be different.

Is any validation I need to take care of ? I got one validation about expected position but is there any other validation is there?

The only validation now is for expected position.

Is there any coding guideline for adding support of another data store

Just follow what you found in existing implemenation, but I will not be heavily strict. I think the "usual F# code" looks more less the same.

What is getting store? From the code I figure it out that Stream type and EventRead is getting stored. But I am not sure if anything I missed.

Sorry, I don't get the question. Can you please elaborate on this?

Thanks again!

Hi, @Dzoukr

I was trying to ask which details we are storing in persistence storage. From code I could make out that EventRead and Stream model are getting stored.

Stream model will be updated every time event happens.

Hope I am right?

Yeah, you are right. Stream metadata keeps the info about whole stream (last updated, last position, etc...). Don't forget that is necessary to have storing both in some kind of transaction - if updating metadata fails, no event is appended in vice versa.

Hi, @Dzoukr

I am able to create most of the function. But couldn't get the JToken part. Why specifically JToken is used. Litedb is failing because it can't de-serialized JToken. As JToken is not having any public constructor.

How, you are serializing / de - serializing them?

I have made following changes to file and remove JToken as input. All test are passing for litedb

namespace CosmoStore

open System
open System.Threading.Tasks
open Newtonsoft.Json.Linq

type ExpectedPosition =
    | Any
    | NoStream
    | Exact of int64

type EventsReadRange =
    | AllEvents
    | FromPosition of int64
    | ToPosition of int64
    | PositionRange of fromPosition:int64 * toPosition:int64

type StreamsReadFilter =
    | AllStreams
    | StartsWith of string
    | EndsWith of string
    | Contains of string

[<CLIMutable>]
type EventRead<'a,'b> = {
    Id : Guid
    CorrelationId : Guid option
    CausationId : Guid option
    StreamId : string
    Position: int64
    Name : string
    Data : 'a
    Metadata : 'b option
    CreatedUtc : DateTime
}

type EventWrite<'a, 'b> = {
    Id : Guid
    CorrelationId : Guid option
    CausationId : Guid option
    Name : string
    Data : 'a
    Metadata : 'b option
}

[<CLIMutable>]
type Stream = {
    Id : string
    LastPosition : int64
    LastUpdatedUtc: DateTime
}

type EventStore<'a,'b> = {
    AppendEvent : string -> ExpectedPosition -> EventWrite<'a,'b> -> Task<EventRead<'a,'b>>
    AppendEvents : string -> ExpectedPosition -> EventWrite<'a,'b> list -> Task<EventRead<'a,'b> list>
    GetEvent : string -> int64 -> Task<EventRead<'a,'b>>
    GetEvents : string -> EventsReadRange -> Task<EventRead<'a,'b> list>
    GetEventsByCorrelationId : Guid -> Task<EventRead<'a,'b> list>
    GetStreams : StreamsReadFilter -> Task<Stream list>
    GetStream : string -> Task<Stream>
    EventAppended : IObservable<EventRead<'a,'b>>
}

Above is surely a breaking changes. So, I don't know if that works out or not. Please have a look.

I also like to ask that common functions like (mapping, validation) should be moved to core so it can easily be used in all implementation?

Hi @kunjee17,

thanks for questions:

Why specifically JToken is used. Litedb is failing because it can't de-serialized JToken.

Historically it is used because Newtonsoft.Json is "industry standard for JSON on .NET" + is internally used for Cosmos DB.

I would rather avoid breaking changes (version 2 is still too young). I am not LiteDb expert, but there must be way how to store json data.

Maybe... you can map it to your internal structure?

[<CLIMutable>]
type EventRead = {
    Id : Guid
    CorrelationId : Guid option
    CausationId : Guid option
    StreamId : string
    Position: int64
    Name : string
    Data : BsonDocument 
    Metadata : BsonDocument option
    CreatedUtc : DateTime
}

And then create JToken from BsonDocument on mapping?

Let me know, please.

I will give it a try. Litedb is storing kind of json format only. And as JToken is not having default constructor it is giving issue while de serialization . I will still give one more try to by pass it.

You did more than good 😂 so I am closing this one now.