Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 169 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,169 @@
# analytics-dotnet-client
The .NET client for Couchbase Enterprise Analytics server
<p align="center">
<img src="assets/couchbase-filled.png" alt="Couchbase" width="80" />
</p>

<h2 align="center">Couchbase Analytics .NET SDK</h2>

The official .NET SDK for Couchbase Analytics.

## Install

Requires .NET 8.0.

```bash
dotnet add package Couchbase.AnalyticsClient
```

## Documentation

- **Getting Started**: see [`docs/getting-started.md`](docs/getting-started.md)
- **API Reference**: see Official API Reference [here](https://docs.couchbase.com/sdk-api/analytics-dotnet-client-1.0.0/)

## Quick start

### Connect

Create a `Cluster` with a connection string and `Credential`. The connection string supports `http` or `https`, multiple hosts, and query/timeout/TLS parameters.

```csharp
using Couchbase.AnalyticsClient;
using Couchbase.AnalyticsClient.HTTP;
using Couchbase.AnalyticsClient.Options;

var credential = Credential.Create("username", "password");

var cluster = Cluster.Create(
connectionString: "https://analytics.my-couchbase.example.com:18095?max_retries=5",
credential: credential,
configureOptions: options => options
.WithTimeoutOptions(timeoutOpts => timeoutOpts
.WithQueryTimeout(TimeSpan.FromSeconds(15)))
.WithSecurityOptions(securityOpts => securityOpts
.WithTrustOnlyCapella())
);
```

> [!NOTE]
> Use `http://host:8095` for non-TLS connections, `https://host:18095` for TLS (or your own custom ports for a load balancer or proxy)
>
> If multiple IP addresses are resolved for a host, a connection will be attempted for a random one. If that connection attempt fails, another IP will be picked to attempt a connection, until all are exhausted.
>
> Connection string parameters include:
> - `timeout.connect_timeout`, `timeout.dispatch_timeout`, `timeout.query_timeout` (in milliseconds)
> - `security.trust_only_pem_file`, `security.disable_server_certificate_verification`, `security.cipher_suites`
> - `max_retries`

### Query

Run an Analytics statement and stream rows:

> [!NOTE]
> Results are streamed by default. Use `QueryOptions.WithAsStreaming(false)` to get a blocking result.

```csharp
using Couchbase.AnalyticsClient.Options;

var result = await cluster.ExecuteQueryAsync(
"SELECT i from ARRAY_RANGE(1, 100) AS i;",
new QueryOptions()
.WithReadOnly(true)
.WithScanConsistency(QueryScanConsistency.RequestPlus)
).ConfigureAwait(false);

await foreach (var row in result.ConfigureAwait(false))
{
Console.WriteLine(row.ContentAs<JsonElement>());
}
```

### Query with parameters

```csharp
var statement = "SELECT * FROM `travel-sample`.inventory.airline WHERE country = $country LIMIT $limit";

var paramResult = await _analytics2Fixture.Cluster.ExecuteQueryAsync(
statement,
new QueryOptions()
.WithNamedParameter("country", "United States")
.WithNamedParameter("limit", 10)
).ConfigureAwait(false);

await foreach (var row in paramResult.ConfigureAwait(false))
{
Console.WriteLine(row.ContentAs<JsonElement>());
}

/** Output:
{"airline":{"id":"airline_19433","type":"airline","name":"XAIR USA","iata":"XA","icao":"XAU","callsign":"XAIR","country":"United States"}}
...
*/
```

### Database and scope context

Target a specific database and scope using `Database(...).Scope(...).ExecuteQueryAsync(...)`:

```csharp
var db = cluster.Database("travel-sample");
var scope = db.Scope("inventory");

var scoped = await scope.ExecuteQueryAsync(
"SELECT id FROM airline LIMIT 5"
).ConfigureAwait(false);

await foreach (var row in scoped.ConfigureAwait(false))
{
Console.WriteLine(row.ContentAs<JsonElement>());
}

/** Output:
{"id":"airline_19433"}
{"id":"airline_137"}
{"id":"airline_18239"}
{"id":"airline_10123"}
{"id":"airline_19290"}
*/
```

### Options

> [!WARNING]
> Option classes are immutable records. Each mutation returns a new instance of the options.

Initialize, or modify options using:

`With` methods return a new instance of the options, to allow chaining:

```csharp
var options = new QueryOptions()
.WithReadOnly(true)
.WithScanConsistency(QueryScanConsistency.RequestPlus);
```

Or use the initializer syntax:
```csharp
var options = new QueryOptions()
{
ReadOnly = true,
ScanConsistency = QueryScanConsistency.RequestPlus
}

// or

options = options with {
ReadOnly = true,
ScanConsistency = QueryScanConsistency.RequestPlus
}
```

### Cleanup

`Cluster` implements `IDisposable`. Dispose when done to release resources:

```csharp
cluster.Dispose();
```

## License

Apache 2.0, see [`LICENSE`](LICENSE).
Binary file added assets/couchbase-filled.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
94 changes: 73 additions & 21 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ This guide shows how to install the package, connect to a Couchbase cluster, and
Add the package to your project:

```bash
dotnet add package Couchbase.Analytics
dotnet add package Couchbase.AnalyticsClient
```

Requires .NET 8.0.

## Connect
### Connect

Create a `Cluster` with a connection string and `Credential`. The connection string supports `http` or `https`, multiple hosts, and query/timeout/TLS parameters.

Expand All @@ -34,19 +34,22 @@ var cluster = Cluster.Create(
);
```

Notes:
- Use `http://host:8095` for non-TLS clusters, `https://host:18095` for TLS (or your own custom ports for a load balancer or proxy)
- If multiple IP addresses are resolved for a host, a connection will be attempted for a random IP address. If a connection attempt fails, another IP will be picked to attempt a connection, until all are exhausted.
- Connection string parameters include:
- `timeout.connect_timeout`, `timeout.dispatch_timeout`, `timeout.query_timeout` (in milliseconds)
- `security.trust_only_pem_file`, `security.disable_server_certificate_verification`, `security.cipher_suites`
- `max_retries`
> [!NOTE]
> Use `http://host:8095` for non-TLS connections, `https://host:18095` for TLS (or your own custom ports for a load balancer or proxy)
>
> If multiple IP addresses are resolved for a host, a connection will be attempted for a random one. If that connection attempt fails, another IP will be picked to attempt a connection, until all are exhausted.
>
> Connection string parameters include:
> - `timeout.connect_timeout`, `timeout.dispatch_timeout`, `timeout.query_timeout` (in milliseconds)
> - `security.trust_only_pem_file`, `security.disable_server_certificate_verification`, `security.cipher_suites`
> - `max_retries`

## Query
### Query

Run an Analytics statement and stream rows:

Note: Results are streamed by default. Use `QueryOptions.WithAsStreaming(false)` to get a blocking result.
> [!NOTE]
> Results are streamed by default. Use `QueryOptions.WithAsStreaming(false)` to get a blocking result.

```csharp
using Couchbase.AnalyticsClient.Options;
Expand All @@ -56,11 +59,11 @@ var result = await cluster.ExecuteQueryAsync(
new QueryOptions()
.WithReadOnly(true)
.WithScanConsistency(QueryScanConsistency.RequestPlus)
);
).ConfigureAwait(false);

await foreach (var row in result.Rows)
await foreach (var row in result.ConfigureAwait(false))
{
Console.WriteLine(row.ContentAs<MyPOCO>());
Console.WriteLine(row.ContentAs<JsonElement>());
}
```

Expand All @@ -69,12 +72,22 @@ await foreach (var row in result.Rows)
```csharp
var statement = "SELECT * FROM `travel-sample`.inventory.airline WHERE country = $country LIMIT $limit";

var paramResult = await cluster.ExecuteQueryAsync(
var paramResult = await _analytics2Fixture.Cluster.ExecuteQueryAsync(
statement,
new QueryOptions()
.WithNamedParameter("country", "United States")
.WithNamedParameter("limit", 10)
);
).ConfigureAwait(false);

await foreach (var row in paramResult.ConfigureAwait(false))
{
Console.WriteLine(row.ContentAs<JsonElement>());
}

/** Output:
{"airline":{"id":"airline_19433","type":"airline","name":"XAIR USA","iata":"XA","icao":"XAU","callsign":"XAIR","country":"United States"}}
...
*/
```

### Database and scope context
Expand All @@ -86,16 +99,55 @@ var db = cluster.Database("travel-sample");
var scope = db.Scope("inventory");

var scoped = await scope.ExecuteQueryAsync(
"SELECT META().id FROM airline LIMIT 5"
);
"SELECT id FROM airline LIMIT 5"
).ConfigureAwait(false);

await foreach (var row in scoped.ConfigureAwait(false))
{
Console.WriteLine(row.ContentAs<JsonElement>());
}

/** Output:
{"id":"airline_19433"}
{"id":"airline_137"}
{"id":"airline_18239"}
{"id":"airline_10123"}
{"id":"airline_19290"}
*/
```

await foreach (var row in scoped.Rows)
### Options

> [!WARNING]
> Option classes are immutable records. Each mutation returns a new instance of the options.

Initialize, or modify options using:

`With` methods return a new instance of the options, to allow chaining:

```csharp
var options = new QueryOptions()
.WithReadOnly(true)
.WithScanConsistency(QueryScanConsistency.RequestPlus);
```

Or use the initializer syntax:
```csharp
var options = new QueryOptions()
{
Console.WriteLine(row.Json.ToString());
ReadOnly = true,
ScanConsistency = QueryScanConsistency.RequestPlus
}

// or

options = options with {
ReadOnly = true,
ScanConsistency = QueryScanConsistency.RequestPlus
}
```

## Cleanup
### Cleanup

`Cluster` implements `IDisposable`. Dispose when done to release resources:

Expand Down
6 changes: 6 additions & 0 deletions tests/Couchbase.Analytics.FunctionalTests/NewTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Couchbase.AnalyticsClient.FunctionalTests;

public class NewTest
{

}
Loading