Skip to content
This repository was archived by the owner on Dec 18, 2023. It is now read-only.
Draft
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
78 changes: 38 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,47 +71,45 @@ I highly recommend taking a looksie at the [examples](https://github.com/Prophet
```csharp
using SurrealDB.Configuration;
using SurrealDB.Driver.Rpc;
using SurrealDB.Models;

// start server: surreal start -b 0.0.0.0:8082 -u root -p root --log debug
// Create a configuration for the sever specified above.
Config cfg = Config.Create()
.WithEndpoint("127.0.0.1:8082")
.WithDatabase("test")
.WithNamespace("test")
.WithBasicAuth("root", "root")
// Tell the configuration to connect to the server using RPC, and without TLS.
.WithRpc(insecure: true).Build();

// Create a RPC database connection with the configuration.
DatabaseRpc db = new(cfg);
// Connect using the defined connection.

// Signin as a namespace, database, or root user;
using DatabaseRpc db = new(Config.Create()
.WithEndpoint("127.0.0.1:8000")
.WithDatabase("test")
.WithNamespace("test")
.WithBasicAuth("root", "root")
.WithRpc()
.Build());

await db.Open();
// Create a struct with the fields we want to insert, nesting is supported.
Person you = new("Max Mustermann", 39, new("Musterstraße 1", 12345, "Musterstadt"), "0123456789", "max@mustermann.de");
// Insert the struct into the database, table = person, id = maxmustermann.
// If id` is not specified it will be random-generated, the id can be read from the response.
RpcResponse create = await db.Create("person:maxmustermann", you);
// Read the struct from the database to verify it was inserted correctly.
RpcResponse select = await db.Select("person:maxmustermann");
if (select.TryGetResult(out Result result)) {
// Prints: {"address":{"city":"Musterstadt","street":"Musterstraße 1","zip":12345},"age":39,"email":"max@mustermann.de","id":"test:maxmustermann","name":"Max Mustermann","phone":"0123456789"}
Console.WriteLine(result.Inner);
Person alsoYou = result.GetObject<Person>();
// Prints: Yes we equals? True
Console.WriteLine($"Yes we equals? {you == alsoYou}");
}


/// <summary>
/// A Person.
/// </summary>
record struct Person(string name, int age, Address address, string phone, string email);

/// <summary>
/// The address of one or more people.
/// </summary>
record struct Address(string street, int zip, string city);

// Create a new person with a random id
var created = await db.Create("person", new {
title = "Founder & CEO",
name = new {
first = "Tobie",
last = "Morgan Hitchcock"
},
marketing = true,
identifier = Random.Shared.Next().ToString("x")
});

// Update a person record with a specific id
var updated = await db.Change("person:jamie", new {
marketing = true,
});

// Select all people records
var poeple = await db.Select("person");

// Perform a custom advanced query
var groups = await db.Query(
"SELECT marketing, count() FROM type::table($tb) GROUP BY markering",
new Dictionary<string, object?> {
["tb"] = "person"
}
);

```

## Coverage
Expand Down
3 changes: 3 additions & 0 deletions SurrealDB.Net.sln
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Models", "src\Models\Models.csproj", "{548AA5BF-FDBE-4491-8A8B-A9285B501E23}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{361F079C-3E1E-41EE-9654-FCA5EEF2BEFB}"
ProjectSection(SolutionItems) = preProject
src\Extensions\Directory.Build.props = src\Extensions\Directory.Build.props
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Service", "src\Extensions\Service\Service.csproj", "{3590BC60-5A31-4AD1-ACAD-C96B94D2E463}"
EndProject
Expand Down
64 changes: 64 additions & 0 deletions examples/BlazorSurveys/BlazorSurveys.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.0.0
MinimumVisualStudioVersion = 16.0.0.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorSurveys.Server", "Server\BlazorSurveys.Server.csproj", "{725FB3BC-9694-41A1-A189-8E60451240EB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorSurveys.Client", "Client\BlazorSurveys.Client.csproj", "{5A6198F1-E2D9-4663-BAFB-72B184758D67}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorSurveys.Shared", "Shared\BlazorSurveys.Shared.csproj", "{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Debug|x64.ActiveCfg = Debug|Any CPU
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Debug|x64.Build.0 = Debug|Any CPU
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Debug|x86.ActiveCfg = Debug|Any CPU
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Debug|x86.Build.0 = Debug|Any CPU
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Release|Any CPU.Build.0 = Release|Any CPU
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Release|x64.ActiveCfg = Release|Any CPU
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Release|x64.Build.0 = Release|Any CPU
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Release|x86.ActiveCfg = Release|Any CPU
{5A6198F1-E2D9-4663-BAFB-72B184758D67}.Release|x86.Build.0 = Release|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Debug|x64.ActiveCfg = Debug|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Debug|x64.Build.0 = Debug|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Debug|x86.ActiveCfg = Debug|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Debug|x86.Build.0 = Debug|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Release|Any CPU.Build.0 = Release|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Release|x64.ActiveCfg = Release|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Release|x64.Build.0 = Release|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Release|x86.ActiveCfg = Release|Any CPU
{725FB3BC-9694-41A1-A189-8E60451240EB}.Release|x86.Build.0 = Release|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Debug|x64.ActiveCfg = Debug|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Debug|x64.Build.0 = Debug|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Debug|x86.ActiveCfg = Debug|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Debug|x86.Build.0 = Debug|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Release|Any CPU.Build.0 = Release|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Release|x64.ActiveCfg = Release|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Release|x64.Build.0 = Release|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Release|x86.ActiveCfg = Release|Any CPU
{BC0E07A9-98E8-4CB8-A350-DE6A6EBF4FC3}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {37068660-CB4F-47DF-9209-41A65384A79E}
EndGlobalSection
EndGlobal
71 changes: 71 additions & 0 deletions examples/BlazorSurveys/Client/App.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
@using System.Threading
@using Microsoft.AspNetCore.SignalR.Client
@implements IAsyncDisposable
@inject HubConnection HubConnection

<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>

@code {
private CancellationTokenSource cts = new();

protected override void OnInitialized()
{
// launch the signalR connection in the background.
// Note we dont want to block the rendering of the app until the connection is established
// nor we want an exception to prevent the entire app from starting
// Therefore we run it in the background without "await"
// See: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/lifecycle?view=aspnetcore-5.0#handle-errors
#pragma warning disable CS4014
ConnectWithRetryAsync(cts.Token);

// Once initialized the retry logic configured in the HubConnection will automatically attempt to reconnect
// However, once it reaches its maximum number of attempts, it will give up and needs to be manually started again
// handling this event will achieve that
// See: https://docs.microsoft.com/en-us/aspnet/core/signalr/dotnet-client?view=aspnetcore-5.0&tabs=visual-studio#handle-lost-connection
HubConnection.Closed += error =>
{
return ConnectWithRetryAsync(cts.Token);
};
}

private async Task<bool> ConnectWithRetryAsync(CancellationToken token)
{
// Keep trying to until we can start or the token is canceled.
while (true)
{
try
{
await HubConnection.StartAsync(token);
return true;
}
catch when (token.IsCancellationRequested)
{
return false;
}
catch
{
// Failed to connect, trying again in 5000 ms.
// This could be a random or incremental interval, similar to the reconnection strategy of the hub itself
// (Note the HubConnection retry strategy does not apply during initial connection, nor once it reaches its max number of attempts)
// See https://docs.microsoft.com/en-us/aspnet/core/signalr/dotnet-client?view=aspnetcore-5.0&tabs=visual-studio#handle-lost-connection
await Task.Delay(5000);
}
}
}

public async ValueTask DisposeAsync()
{
cts.Cancel();
cts.Dispose();
await HubConnection.DisposeAsync();
}
}
21 changes: 21 additions & 0 deletions examples/BlazorSurveys/Client/BlazorSurveys.Client.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.9" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.9" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Shared\BlazorSurveys.Shared.csproj" />
</ItemGroup>

</Project>
106 changes: 106 additions & 0 deletions examples/BlazorSurveys/Client/Pages/AddSurvey.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
@page "/add-survey"
@using BlazorSurveys.Shared
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.Extensions.Logging
@inject SurveyHttpClient SurveyHttpClient
@inject NavigationManager NavigationManager
@inject ILogger<AddSurvey> Logger

<EditForm EditContext="@editContext" OnSubmit="@OnSubmit">
@* Use the experimental ObjectGraphDataAnnotationsValidator which allows to validate complex nested models *@
@* <DataAnnotationsValidator /> *@
<ObjectGraphDataAnnotationsValidator />
<div class="@(editContext.GetValidationMessages().Any() ? "alert alert-danger pb-0" : "")">
<ValidationSummary />
</div>

<div class="form-group">
<label for="inputTitle">Title</label>
<InputText id="inputTitle" class="form-control" @bind-Value="survey.Title" />
@if(editContext.GetValidationMessages(() => survey.Title).Any()){
<div class="invalid-feedback">
@editContext.GetValidationMessages(() => survey.Title).First()
</div>
}
</div>

<div class="form-group">
<label for="inputMinutes">Minutes</label>
<InputNumber id="inputMinutes" class="form-control" @bind-Value="survey.Minutes" />
@if(editContext.GetValidationMessages(() => survey.Minutes).Any()){
<div class="invalid-feedback">
@editContext.GetValidationMessages(() => survey.Minutes).First()
</div>
}
</div>

<label>Options</label>
@foreach (OptionCreateModel option in survey.Options)
{
<div class="input-group mb-3">
<InputText id="inputMinutes" class="form-control" @bind-Value="option.OptionValue" />
<div class="input-group-append">
<button class="btn btn-outline-primary" type="button" @onclick="@(() => survey.RemoveOption(option))">Remove</button>
</div>
@if(editContext.GetValidationMessages(() => option.OptionValue).Any()){
<div class="invalid-feedback">
@editContext.GetValidationMessages(() => option.OptionValue).First()
</div>
}
</div>
}
<p><button class="btn btn-primary" type="button" @onclick="@(() => survey.AddOption())"><i class="oi oi-plus" /> Add Option</button></p>

<p>
<button type="submit" class="btn btn-primary float-right">Submit</button>
</p>
</EditForm>

@code {
private AddSurveyModel survey = new();
private EditContext editContext;

protected override void OnInitialized()
{
editContext = new EditContext(survey);
editContext.SetFieldCssClassProvider(new BootstrapFieldClassProvider());
}
private async Task OnSubmit()
{
// even though the server will validate the AddSurveyModel, check client side that the model is valid
if (!editContext.Validate()) return;

try
{
HttpResponseMessage response = await SurveyHttpClient.AddSurvey(survey);
if (response.IsSuccessStatusCode)
{
NavigationManager.NavigateTo("");
}
else
{
// TODO! check if received a Bad status request
// and if so, show the errors returned from the server in the alert box
// See: https://docs.microsoft.com/en-us/aspnet/core/blazor/forms-validation?view=aspnetcore-5.0#server-validation
}
}
catch (Exception ex)
{
Logger.LogError("Error: {Message}", ex.Message);
}

}

// This class lets us modify the CSS class that will be added to the input elements
// when the properties they are bound to are invalid
// This way we can add the "is-invalid" to the input elements
// See: https://docs.microsoft.com/en-us/aspnet/core/blazor/forms-validation?view=aspnetcore-5.0#custom-validation-class-attributes
private class BootstrapFieldClassProvider : FieldCssClassProvider
{
public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier)
{
bool isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();
return isValid ? "" : "is-invalid";
}
}
}
Loading