Form.Attributes 0.0.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package Form.Attributes --version 0.0.1
NuGet\Install-Package Form.Attributes -Version 0.0.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Form.Attributes" Version="0.0.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Form.Attributes --version 0.0.1
#r "nuget: Form.Attributes, 0.0.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Form.Attributes as a Cake Addin
#addin nuget:?package=Form.Attributes&version=0.0.1

// Install Form.Attributes as a Cake Tool
#tool nuget:?package=Form.Attributes&version=0.0.1

NuGet Status

F# Object Relational Mapper

An attribute based ORM for fsharp.

Usage

To start, enumerate your databases:

type Contexts = 
    | Database1 = 1
    | Database2 = 2

We use enumeration here as Unions are not supported by attributes as of yet. The number that each database is set to doesn't really matter, but at the moment this is the best way we have found to generalize and organize contextualized attributes.

Next, use attributes to perform your domain modeling:

[<Table("User", Contexts.Database1)>]
[<Table("Users", Contexts.Database2)>]
type User = 
    { Id : int
      [<Column("Name", Contexts.Database1)>]
      [<Column("Login", Contexts.Database2)>]
      Name : string
      [<Column("Secret", Contexts.Database1)>]
      Password : string
      Salt : string
    }

Table and Column attributes take a name and a context. The name must match that of the relevant object in the database which is referred to by the given context; that is to say, the User type refers to a table called "User" in Database1, and "Users" in Database2. If no attribute is given, the underlying logic will default to the name of the type/field, so if you use the same names in your project and your database(s), no Table/Column attribute is necessary; i.e., the "Id" field will be assumed to map to an "Id" field in both the "User" table in Database1, and the same in the "Users" table in Database2.

Before we connect, we must also declare some OrmStates. We will need one for each context:

let db1State = PSQL(db1ConnectionString, Contexts.Database1)
let db2State = MSSQL(db2ConnectionString, Contexts.Database2)

The connection strings should just be given as strings, deliver these however you see fit (we recommend either putting them in a .env file or setting an environmental variable the will deliver the connection string, we may add some helper functions for this later).

Now we can do some querying:

selectAll<User> db1State |> printfn "%A"

This should send a SELECT * query to the db1./.User table, if everything was setup correctly. Keep in mind that our querying functions return Result<[]^T, {| Message |}>, so be prepared to handle those accordingly.

We also include a custom query framework; an example:

let query =
    { clauses = 
        [ select<User>
        ; from<User>
        ; join<User> [First ("Id", Equals "42"); And ("Name", NotEquals "'Jim'")]
        ] 
    }.Compile db1State

The compilation returns a string, and if printed the above should be:

"SELECT "Id", "Name", "Secret", "Salt" FROM "User" JOIN "User" On "Id" = 42 AND "Name" = 'Jim'"

Obviously, you may need to specify Schema in table declarations. We are currently ruminating over the idea of a schema attribute, but for now just add the schema name to the table attribute:

[<Table("SchemaName.User", Contexts.Database1)>]

and the logic will sort it all out:

"SELECT "Id", "Name", "Secret", "Salt" FROM "SchemaName"."User" JOIN "SchemaName"."User" On "Id" = 42 AND "Name" = 'Jim'"

Disambiguation of columns will be necessary for joins, we will be adding that soon.

Once you have the query you need, simply execute it:

let rowsAffected = execute query db1State //This is a non-query execution, does not return a result set
let queryResults = executeReader query generatereader db1State //This DOES return a result set, in this case a Result<[]User, {| Message |}> 

Though this package itself awaits full testing, we have taken most of these pieces from other projects which have been thoroughly tested, so this package should work more or less out of the box.

Contribution Guidelines

Currently no strict guidelines, just open a pull request or an issue. Feel free to shoot us an email if you have any questions!

Note:

  • Contributions are welcome!
  • This has yet to be tested fully.
  • Under active development.
Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Form.Attributes:

Package Downloads
Form

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
0.0.15 91 3/20/2024
0.0.14 91 3/20/2024
0.0.13 97 3/14/2024
0.0.12 99 2/27/2024
0.0.11.1 124 4/25/2024
0.0.11 198 1/18/2024
0.0.9 87 1/17/2024
0.0.8 173 9/17/2023
0.0.7 167 8/2/2023
0.0.6 136 8/2/2023
0.0.5 136 8/2/2023
0.0.4 146 8/2/2023
0.0.3 238 5/18/2023
0.0.2 135 5/16/2023
0.0.1 150 5/6/2023