Rezoom 2.0.0

dotnet add package Rezoom --version 2.0.0
                    
NuGet\Install-Package Rezoom -Version 2.0.0
                    
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="Rezoom" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Rezoom" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Rezoom" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Rezoom --version 2.0.0
                    
#r "nuget: Rezoom, 2.0.0"
                    
#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.
#:package Rezoom@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Rezoom&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Rezoom&version=2.0.0
                    
Install as a Cake Tool

What's this?

Rezoom is a library intended to reduce the pain of dealing with data that lives across a latency boundary.

Horrors of latency

Common examples of this nightmare include SQL databases, NoSQL databases, and web APIs.

It tends to be hard to write abstractions over these data sources because the round-trip time dominates all other performance concerns, and it's impossible to optimize without breaking your API.

If somebody is calling GetUserDetails(userId) in a loop for 500 different users, you really can't help them other than by convincing them to switch to GetMultipleUserDetails(all500userIds).

Rezoom lets you write little units of business logic called Plans (like the aforementioned GetUserDetails), which you can then glue together into larger plans. It'll handle converting the 500 independent GetUserDetails calls into one GetMultipleUserDetails call. It also de-duplicates redundant requests: for example if multiple functions need to query for the current user's permissions, only one such query will actually be executed.

Show me an example so I know whether to care

Here's some contrived example code. You can write a Rezoom wrapper library for any data source, but it comes with one called Rezoom.SQL that statically typechecks SQL and infers its caching behavior.

type GetPerson = SQL<"select * from People where Id = @id">
type GetCompany = SQL<"select * from Companies where Id = @id">

/// Gets a person and their employer. This implementation takes 2 round trips.
let getPersonAndEmployer (personId : int) : (GetPerson.Row * GetCompany.Row) Plan =
    plan {
        // One round trip.
        let! person = GetPerson.Command(id = personId).ExactlyOne()
        // Another round trip.
        let! employer = GetCompany.Command(id = person.EmployerId).ExactlyOne()
        return (person, employer)
    }

let example =
    plan {
        // Two round-trips: one to get both users, another to get both employers.
        // If the two users have the same employer, the 2nd round-trip will only include one SELECT statement.
        let! (user1, employer1), (user2, employer2) =
            getPersonAndEmployer 1, getPersonAndEmployer 2
        printfn "%s is employed by %, %s by %s"
            user1.Name, employer1.Name
            user2.Name, employer2.Name

        // Two more round trips: again, the user queries all share one, and the employer queries share the next.
        for id in batch [ 3; 4; 5; 6 ] do
            let! user, employer = getPersonAndEmployer id
            printfn "%s is employed by %s" user.Name, employer.Name
    }

Pretty neat, huh? How about this?

type UpdateCompanies = SQL<"update Companies set LastUpdatedUtc = SysUtcDateTime() where Id = 27">

let example2 =
    plan {
        // Two round-trips: one for the user, one for the employer.
        let! (user1, employer1) =
            getPersonAndEmployer 1

        // Zero round trips, because both query results are cached.
        let! (user1Again, employer1Again) =
            getPersonAndEmployer 1

        // Invalidates the cache for all queries dependent on the Companies table.
        // This is automatically deduced by the SQL<"query string"> type provider.
        do! UpdateCompanies.Command().Plan()

        // One round-trip: user is still cached, but we have to reload the employer.
        let! (user1Again, employer1Again) =
            getPersonAndEmployer 1

        return 0
    }

"Now, hang on a minute," you might be asking your computer screen. "Where's this stuff being cached? What if some other code updates a table and now the cache is invalid?"

When you write a plan block nothing happens until you execute it with Execution.execute(plan). The cache is local to that execution, which is also implicitly wrapped in a transaction. So, the cache is not for keeping information across, say, multiple requests to your website.

It's to eliminate the temptation to explicitly pass around loaded data, cluttering your API in an attempt to save queries.

The idea is to let you write very fine-grained APIs that take the bare minimum of information (like deleteSlide : SlideId -> unit Plan) but can be composed together without creating a performance nightmare.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  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 is compatible.  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.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Rezoom:

Package Downloads
Rezoom.SQL.Mapping

Mapping / data reader infrastructure for Rezoom.SQL.

Rezoom.SQL.Compiler

Compiler and dialect translators for Rezoom.SQL.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 336 5/16/2026
1.0.1 1,309 6/3/2019
1.0.0 1,487 7/4/2018
0.4.2 5,360 7/19/2017
0.4.1 2,190 5/12/2017
0.4.0 1,368 5/12/2017
0.3.0 4,570 3/22/2017
0.2.1 3,147 3/12/2017
0.2.0 1,360 3/10/2017
0.1.0 1,358 3/9/2017

Modernized for the 2026 .NET ecosystem after a long dormancy. Multi-targets netstandard2.0, net8.0, and net10.0. Drops embedded TaskBuilder.fs in favor of FSharp.Core's built-in `task { }` (requires FSharp.Core 8.0.401+). Replaces the custom IServiceConfig with the standard IServiceProvider. Adds PlanExecutor for DI-friendly plan execution. ServiceContext renamed to PlanContext. Breaking changes for code that used the old service-config API.