DataOil.Client 0.2.2

Prefix Reserved
dotnet add package DataOil.Client --version 0.2.2
                    
NuGet\Install-Package DataOil.Client -Version 0.2.2
                    
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="DataOil.Client" Version="0.2.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DataOil.Client" Version="0.2.2" />
                    
Directory.Packages.props
<PackageReference Include="DataOil.Client" />
                    
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 DataOil.Client --version 0.2.2
                    
#r "nuget: DataOil.Client, 0.2.2"
                    
#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 DataOil.Client@0.2.2
                    
#: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=DataOil.Client&version=0.2.2
                    
Install as a Cake Addin
#tool nuget:?package=DataOil.Client&version=0.2.2
                    
Install as a Cake Tool

DataOil.Client

The Data Oil client for .NET. One statement over rows, vectors, keywords and relationships, streamed as NDJSON, with the two tenancy headers, typed errors and the retry a lost race needs built in. net8.0 and net10.0; no dependencies beyond the framework.

dotnet add package DataOil.Client

Sixty seconds

using DataOil.Client;

using DataOilClient client = new("https://acme.dataoil.tech", "bookshop", "your-account", "your-password");
// or, with an API key:  new("https://acme.dataoil.tech", "bookshop", "dot_...")

await client.StatementAsync(
    "INSERT INTO Book SET isbn = :isbn, title = :title",
    new { isbn = "978-cs", title = "From C#" });

foreach (JsonElement row in await client.StatementAsync("SELECT isbn, title FROM Book ORDER BY isbn"))
{
    Console.WriteLine($"{row.GetProperty("isbn")} {row.GetProperty("title")}");
}

// A large scan streams, and follows the cursor across pages.
await foreach (JsonElement row in client.QueryAsync("SELECT FROM Report WHERE filedAt > :since", new { since = "2026-01-01" }, pageSize: 2000))
{
    Handle(row);
}

// One statement over keywords, meaning and a column.
var hits = await client.StatementAsync("""
    SELECT title, VECTOR_DISTANCE(embedding, EMBED(:q), 'cosine') AS distance, $score AS keywordScore
    FROM Report
    WHERE SEARCH_INDEX('Report[body]', :q) = true AND filedAt > date('2026-01-01')
    ORDER BY distance LIMIT 10
    """, new { q = "casing failure" });

What it does for you

The two headers X-Job-ID and X-Database on every call. The engine refuses a call without either, one at a time. WithJob("nightly-42") names a batch.
NDJSON, streamed QueryAsync yields rows as they arrive and sends the cursor back for the next page. The trailer line is never a row. StatementAsync reads one page into a list and refuses to pretend a page that did not finish was the whole answer.
Typed errors Every refusal is a DataOilException with Status, ErrorCode (the stable code, e.g. TypeNotFound, RequestQuotaExceeded), Detail, CorrelationId, Arguments (a quota's used, allowed, resetsAt) and Retryable. Four subclasses: DataOilAuthorizationException (401/403), DataOilNotFoundException (404), DataOilConflictException (409/412), DataOilQuotaException (429/507, with RetryAfter).
The 409 retry A lost race is answered 409 with X-Retryable: true; nothing was written, and the same request a moment later succeeds. It is retried with full jitter on its own budget (RetryPolicy: 5 attempts, 100 ms doubling to 5 s). A duplicate key (X-Retryable: false) is never retried. 429 waits what Retry-After says when that is inside the budget; 503 is retried like a race. Nothing else is.

The rest of the surface

JsonElement record = await client.CreateAsync("Book", new { isbn = "1", title = "A" });   // {rid, type, properties}
JsonElement read = await client.GetAsync(record.GetProperty("rid").GetString()!);
await client.DeleteAsync(record.GetProperty("rid").GetString()!);

await client.BatchAsync([new("INSERT INTO Book SET isbn = :i", new { i = "1" }), new("INSERT INTO Book SET isbn = :i", new { i = "2" })]);

string tx = await client.BeginTransactionAsync();
await client.StatementAsync("INSERT INTO Book SET isbn = '3'", transaction: tx);
await client.CommitAsync(tx);                       // or RollbackAsync

JsonElement schema = await client.SchemaAsync();    // {types:[{name, properties:[{name,type,description}], description}]}
JsonElement prose = await client.SchemaNarrativeAsync();
JsonElement key = await client.MintTokenAsync("the reporting job", rights: ["read"], lifetime: TimeSpan.FromDays(30));
JsonElement answer = await client.AskAsync("which reports mention casing?", rows, statement: sql);   // the tenant's own model, sent only the rows you read

JsonElement anything = await client.RequestAsync(HttpMethod.Get, "api/v2/databases/bookshop/statistics");

DataOilClientOptions takes an HttpClient you own (for a deployment on its own certificate authority, a proxy, or a test) and a RetryPolicy.

Keeping a schema (0.2.0)

DataOilSchemaAnswer first = await client.GetSchemaAsync();                 // what this caller may read, typed
DataOilSchema schema = first.Schema!;                                       // Version, Types, Properties, Indexes

DataOilSchemaAnswer again = await client.GetSchemaAsync(ifNoneMatch: first.Tag);
// again.NotModified is true when nothing this caller may read has changed: one small request

int version = await client.SchemaVersionAsync();                            // the number alone
DataOilCapabilities can = await client.CapabilitiesAsync();                 // functions, types, joins, transactions, paging

client.ExpectedSchemaVersion = schema.Version;                              // sent as X-Schema-Version
// a statement checked against a version the schema has moved past is refused before it runs:
// DataOilException.IsSchemaMoved

The tag is a hash of the answer, so it moves when a grant changes what this caller may read, which moves no schema version. SchemaVersionAsync says whether the schema moved; only the tag says whether your view of it did. These are what the Entity Framework Core provider, DataOil.EntityFrameworkCore, is built on.

Tests

dotnet test runs 27 checks against a stub that answers exactly what the engine answers - NDJSON with its trailer, problem documents with X-Retryable, a 429 with Retry-After. Set DATAOIL_URL, DATAOIL_DATABASE and a credential (and DATAOIL_CA for a self-signed deployment) and one more creates a type, writes, streams, refuses and drops against a running engine.

The reference manual is at https://documents.dataoil.tech/tenant/.

Source and licensing

Questions, issues and releases: https://documents.dataoil.tech/tenant/ and info@dataoil.tech. The packages are published to the public registries as compiled packages; their source is not published.

This library is proprietary and licensed only for legitimate use with Data Oil, under the Data Oil Software Licence (see LICENSE): copying, modifying, redistributing or reverse engineering it, and any attack on or unauthorised access to the platform, are prohibited. Data Oil itself is a commercial service of MaxDragon Technology, and using it needs a credential issued under the Data Oil customer agreement. The library grants no right to the service, and the service applies its own rights, budgets and audit to every credential. The NOTICE file in the package has the full statement, the trademark note and the third-party components.

Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on DataOil.Client:

Package Downloads
DataOil.EntityFrameworkCore

The Entity Framework Core provider for Data Oil. It learns each database's schema at run time over the engine's own API, validates the application's model against it, translates LINQ to the engine's dialect, and saves with the record version as the concurrency token.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.2 117 10/24/2026