Giter Club home page Giter Club logo

marten.fsharp's Introduction

Marten.FSharp

A set of FSharp wrappers around Marten (Postgresql as a Document Database and Event Store for .Net Applications )

The API is a work in progress and will change as people give me feedback.

The goal is to be similar to https://github.com/fsprojects/FSharp.Control.Reactive.

You can find working examples in the the tests

Builds

GitHub Actions
GitHub Actions
Build History

NuGet

Package Stable Prerelease
Marten.FSharp NuGet Badge NuGet Badge

marten.fsharp's People

Contributors

baronfel avatar forki avatar rikace avatar sheridanchris avatar theangrybyrd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

marten.fsharp's Issues

Document APIs

We should document the apis and show which methods they wrap

IsOneOf failing in filter

IsOneOf fails

    testCase'
        "filter IsOneOf" <|
            fun (db,store) ->
                let expectedDog = saveDog' store
                let names = [|expectedDog.Name; "Fido"; "Snape"|]
                use session = store.OpenSession()
                let actualDog =
                    session
                    |> Session.query<Dog>
                    |> Queryable.filter <@fun d -> d.Name.IsOneOf(names) @>
                    |> Queryable.head
                Expect.equal expectedDog actualDog  "Should be one dog!"
Unable to cast object of type 'System.Linq.Expressions.PropertyExpression' to type 'System.Linq.Expressions.LambdaExpression'.
   at Marten.Lambda.translateExpr(Expression linq) in Marten.FSharp/src/Marten.FSharp/Marten.FSharp.fs:line 47
   at Marten.Lambda.translateExpr(Expression linq) in Marten.FSharp/src/Marten.FSharp/Marten.FSharp.fs:line 47
   at Marten.Queryable.filter[a](FSharpExpr`1 f, IQueryable`1 q) in Marten.FSharp/src/Marten.FSharp/Marten.FSharp.fs:line 227
   at [email protected](Tuple`2 tupledArg) in Marten.FSharp/tests/Marten.FSharp.Tests/Tests.fs:line 277
   at Tests.API [email protected](Tuple`2 x) in Marten.FSharp/tests/Marten.FSharp.Tests/Tests.fs:line 824
   at [email protected](AsyncParams`1 args)

Flesh out Patch Api

Currently the patch api only supports inc incPlural and set. Marten has added many other operations that we should wrap.

A more functional way of including related documents

As you can see here including related documents requires a separate mutable binding.

I wonder if there's a way to accomplish the same effect while giving the consumer a tuple value of 'entity * 'included
(or something similar)

Add more pipeline opportunities

Find areas in the codebase to add pipeline opportunities.

For example:
session functions like deleteX and storeX return unit. Instead, they should probably return the session.

Before:

let storeUserAsync (user: User) (documentSession: IDocumentSession) =
    documentSession |> Session.storeSingle user
    documentSession |> Session.saveChangesAsync

After:

let storeUserAsync (user: User) (documentSession: IDocumentSession) =
    documentSession
    |> Session.storeSingle user
    |> Session.saveChangesAsync

The only downside is, this will cause warnings as existing code will be ignoring the return values.
Also, in some instances you'd want to ignore the return value, for various reasons... maybe separate functions can be used???
I'm not sure.

Inconsistent naming

There is deleteBy and countWhere that allow predicates to filter. We should consider either doing xxxBy or xxxWhere to keep naming consistent.

Marten.Fsharp should support Foreign Key expressions

In the Marten docs

var store = DocumentStore.For(_ =>
{
    _.Connection("some database connection");

    // In the following line of code, I'm setting
    // up a foreign key relationship to the User document
    _.Schema.For<Issue>().ForeignKey<User>(x => x.AssigneeId);
});

The x => x.AssigneeId is of type System.Linq.Expressions.Expression<Func<Alarm,obj>> which can be translated from a Microsoft.Fsharp.Quotations.Expr<'a -> obj>

The ForeignKey method currently lives at https://github.com/JasperFx/marten/blob/6fc1c4e84fb19f2cef0144664ecd5f73d030117b/src/Marten/MartenRegistry.cs#L269-L277

Using F# Record types as named parameters

As of now, you can't use named parameter queries easily from F# because the parameter handler looks for anonymous objects which F# doesn't support.

The code for detecting anonymous types just looks to see if the object has a namespace. You can do this from F# by declaring types in a module only file like

module Parameters

type ByName = {
    name : string
}

but this is not obvious nor optimal.

I have an Stackoverflow question about detecting F# record types from C# at runtime to see if we can maybe add a detection to Marten main. If that's not easy/possible we should consider alternatives.

Incorrect index created for Datetime option

For following type

type User = {
    Id : Guid
    Username : string
    Password : string    
    DOB : DateTime option
}

I define store as shown below

let store = DocumentStore.For(fun x -> 
    x.AutoCreateSchemaObjects <- AutoCreate.CreateOrUpdate
    x.Connection(ConnecitonString)
    x.Schema.For<User>().Index(fun x -> x.Username :> obj) |> ignore
    x.Schema.For<User>().Index(fun x -> x.DOB :> obj)|> ignore
    )

The index for DOB is created as

CREATE INDEX mt_doc_database_user_idx_dob
  ON public.mt_doc_database_user
  USING btree
  (((data ->> 'DOB'::text)::jsonb));

this should be as shown below

CREATE INDEX mt_doc_database_user_idx_dob
  ON public.mt_doc_database_user
  USING btree
  (mt_immutable_timestamp(data ->> 'DOB'::text));

Migrate quotations to anonymous functions

There are some instances where expressions are required and quotations + Lambda.ofArity1 could be of use... especially considering the nuances of calling C# overloads in F#.

Here's a practical example

options
    .Schema
    .For<Post>()
    .FullTextIndex(ofArity1 <@ fun post -> box post.Headline @>)

This compiles while the equivalent anonymous function: fun post -> ... does not.

Marten Discriminated Union as Event Type or Each Discriminated Union Case as Event Type?

I recently found out that discrimated unions does not work well with aggregation in Marten:
https://stackoverflow.com/questions/56479902/f-marten-does-not-load-the-aggregate

For a given discriminated union:

type AccountCreation = {
    Owner: string
    AccountId: Guid
    CreatedAt: DateTimeOffset
    StartingBalance: decimal
}

type Transaction = {
    To: Guid
    From: Guid
    Description: string
    Time: DateTimeOffset
    Amount: decimal
}

type AccountEvent =
    | AccountCreated of AccountCreation
    | AccountCredited of Transaction
    | AccountDebited of Transaction

and the aggregate:

type Account() =
    member val Id = Unchecked.defaultof<Guid> with get,set
    member val Owner = Unchecked.defaultof<string> with get,set
    member val Balance = Unchecked.defaultof<decimal> with get,set
    member val CreatedAt = Unchecked.defaultof<DateTimeOffset> with get,set
    member val UpdatedAt = Unchecked.defaultof<DateTimeOffset> with get,set

    member this.Apply(accountCreation: AccountCreation) =
        this.Id <- accountCreation.AccountId
        this.Owner <- accountCreation.Owner
        this.Balance <- accountCreation.StartingBalance
        this.CreatedAt <- accountCreation.CreatedAt
        this.UpdatedAt <- accountCreation.CreatedAt     

I am not sure what experienced F# folks recommend:

options.Events.AddEventType(typeof<AccountEvent>)
  • pros: can use pattern matching for the kind of event I have (when fetching the stream of events), hence AccountCredited and AccountDebited can be discriminated against each other even if they have the same type.
  • cons: loosing the possibility to have the projections saved in DB (performance if the projection is going through a lot of data), session.LoadAsync<Account>(id) will return null .

or

options.Events.AddEventType(typeof<AccountCreation>)
options.Events.AddEventType(typeof<Transaction>)
  • pros: the possibility to have the projections saved in DB: session.LoadAsync<Account>(id) will return the right value.
  • cons: loosing the possibility to discriminate AccountCredited and AccountDebited against each other when fetching the stream if they have the same type, it forces to have a different record type definition for each.

Add support for new IQueryable functions that Marten supports

  • Min: Async/Task/TaskCt
  • Max: Async/Task/TaskCt
  • Average: Average/Async/Task/TaskCt
  • Sum: Sum/Async/Task/TaskCt
  • SelectMany: SelectMany
  • Distinct: Distinct
  • MatchesSql: MatchesSql (maybe make a function that takes the query sql and any parameters as separate arguments?)

In addition, we probably want to open the various object-extension namespaces in Marten:

  • Marten.Linq.MatchesSql
  • Marten.Linq.SoftDeletes
  • Marten.Linq.LastModified

in order to make it simpler on callers to use the extensions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.