Compare commits
2 Commits
3.11.0
...
3.10.0-alpha
| Author | SHA1 | Date | |
|---|---|---|---|
| 3fbd9c17ba | |||
| 937eb94730 |
@@ -35,6 +35,7 @@ public sealed class Client : ISpeckleGraphQLClient, IClient
|
||||
public WorkspaceResource Workspace { get; }
|
||||
public ServerResource Server { get; }
|
||||
public FileImportResource FileImport { get; }
|
||||
public IngestResource Ingest { get; }
|
||||
|
||||
public Uri ServerUrl => new(Account.serverInfo.url);
|
||||
|
||||
@@ -71,6 +72,7 @@ public sealed class Client : ISpeckleGraphQLClient, IClient
|
||||
Workspace = new(this);
|
||||
Server = new(this);
|
||||
FileImport = new(this, blobApiFactory.Create(account));
|
||||
Ingest = new(this);
|
||||
}
|
||||
|
||||
[AutoInterfaceIgnore]
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace Speckle.Sdk.Api.GraphQL.Inputs;
|
||||
|
||||
public record IngestCreateInput(
|
||||
string fileName,
|
||||
int? maxIdleTimeoutMinutes,
|
||||
string modelId,
|
||||
string projectId,
|
||||
string sourceApplication,
|
||||
string sourceApplicationVersion,
|
||||
IReadOnlyDictionary<string, object?> sourceFileData
|
||||
);
|
||||
|
||||
public record IngestFinishInput(string id, string? message, string objectId, string projectId);
|
||||
|
||||
public record IngestErrorInput(string errorReason, string errorStacktrace, string id, string projectId);
|
||||
|
||||
public record CancelRequestInput(string id, string projectId);
|
||||
|
||||
public record IngestUpdateInput(string id, double? progress, string? progressMessage, string projectId);
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Speckle.Sdk.Api.GraphQL.Models;
|
||||
|
||||
public sealed class Ingest
|
||||
{
|
||||
public required DateTime createdAt { get; init; }
|
||||
public required string errorReason { get; init; }
|
||||
public required string errorStacktrace { get; init; }
|
||||
public required string fileName { get; init; }
|
||||
public required string id { get; init; }
|
||||
public required long maxIdleTimeoutMinutes { get; init; }
|
||||
public required string modelId { get; init; }
|
||||
public required Dictionary<string, object?> performanceData { get; init; }
|
||||
public required double progress { get; init; }
|
||||
public required string? progressMessage { get; init; }
|
||||
public required string projectId { get; init; }
|
||||
public required string sourceApplication { get; init; }
|
||||
public required string sourceApplicationVersion { get; init; }
|
||||
public required Dictionary<string, object?> sourceFileData { get; init; }
|
||||
public required string status { get; init; }
|
||||
public required DateTime updatedAt { get; init; }
|
||||
public required string versionId { get; init; }
|
||||
public required LimitedUser user { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
using GraphQL;
|
||||
using Speckle.Sdk.Api.GraphQL.Inputs;
|
||||
using Speckle.Sdk.Api.GraphQL.Models;
|
||||
using Speckle.Sdk.Api.GraphQL.Models.Responses;
|
||||
using Version = Speckle.Sdk.Api.GraphQL.Models.Version;
|
||||
|
||||
namespace Speckle.Sdk.Api.GraphQL.Resources;
|
||||
|
||||
public sealed class IngestResource
|
||||
{
|
||||
private readonly ISpeckleGraphQLClient _client;
|
||||
|
||||
internal IngestResource(ISpeckleGraphQLClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
/// <param name="modelId"></param>
|
||||
/// <param name="projectId"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<ResourceCollection<Ingest>> GetIngests(
|
||||
string modelId,
|
||||
string projectId,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
query GetIngest($modelId: String!, $projectId: String!) {
|
||||
data:project(id: $projectId) {
|
||||
data:model(id: $modelId) {
|
||||
data:ingests {
|
||||
cursor
|
||||
items {
|
||||
createdAt
|
||||
errorReason
|
||||
errorStacktrace
|
||||
fileName
|
||||
id
|
||||
maxIdleTimeoutMinutes
|
||||
modelId
|
||||
performanceData
|
||||
progress
|
||||
progressMessage
|
||||
projectId
|
||||
sourceApplication
|
||||
sourceApplicationVersion
|
||||
sourceFileData
|
||||
status
|
||||
updatedAt
|
||||
versionId
|
||||
user {
|
||||
avatar
|
||||
bio
|
||||
company
|
||||
id
|
||||
name
|
||||
role
|
||||
verified
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
var request = new GraphQLRequest { Query = QUERY, Variables = new { modelId, projectId } };
|
||||
|
||||
var response = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<ResourceCollection<Ingest>>>>>(
|
||||
request,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return response.data.data.data;
|
||||
}
|
||||
|
||||
/// <param name="input"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<bool> Update(IngestUpdateInput input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
mutation IngestUpdate($projectId: ID!, $input: IngestUpdateInput!) {
|
||||
data: projectMutations {
|
||||
data: ingestMutations(projectId: $projectId) {
|
||||
data: update(input: $input)
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GraphQLRequest request = new() { Query = QUERY, Variables = new { input, input.projectId } };
|
||||
|
||||
var res = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<bool>>>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return res.data.data.data;
|
||||
}
|
||||
|
||||
/// <param name="input"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<Ingest> Create(IngestCreateInput input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
mutation IngestCreate($projectId: ID!, $input: IngestCreateInput!) {
|
||||
data: projectMutations {
|
||||
data:ingestMutations(projectId: $projectId) {
|
||||
data:create(input: $input) {
|
||||
createdAt
|
||||
errorReason
|
||||
errorStacktrace
|
||||
fileName
|
||||
id
|
||||
maxIdleTimeoutMinutes
|
||||
modelId
|
||||
performanceData
|
||||
progress
|
||||
progressMessage
|
||||
projectId
|
||||
sourceApplication
|
||||
sourceApplicationVersion
|
||||
sourceFileData
|
||||
status
|
||||
updatedAt
|
||||
versionId
|
||||
user {
|
||||
avatar
|
||||
bio
|
||||
company
|
||||
id
|
||||
name
|
||||
role
|
||||
verified
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GraphQLRequest request = new() { Query = QUERY, Variables = new { input, input.projectId } };
|
||||
|
||||
var res = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<Ingest>>>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return res.data.data.data;
|
||||
}
|
||||
|
||||
/// <param name="input"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<Version> End(IngestFinishInput input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
mutation IngestEnd($projectId: ID!, $input: IngestFinishInput!) {
|
||||
data: projectMutations {
|
||||
data:ingestMutations(projectId: $projectId) {
|
||||
data:end(input: $input) {
|
||||
id
|
||||
referencedObject
|
||||
message
|
||||
sourceApplication
|
||||
createdAt
|
||||
previewUrl
|
||||
authorUser {
|
||||
id
|
||||
name
|
||||
bio
|
||||
company
|
||||
verified
|
||||
role
|
||||
avatar
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GraphQLRequest request = new() { Query = QUERY, Variables = new { input, input.projectId } };
|
||||
|
||||
var res = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<Version>>>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return res.data.data.data;
|
||||
}
|
||||
|
||||
/// <param name="input"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<bool> Error(IngestErrorInput input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
mutation IngestError($projectId: ID!, $input: IngestErrorInput!) {
|
||||
data: projectMutations {
|
||||
data:ingestMutations(projectId: $projectId) {
|
||||
data:error(input: $input)
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GraphQLRequest request = new() { Query = QUERY, Variables = new { input, input.projectId } };
|
||||
|
||||
var res = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<bool>>>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return res.data.data.data;
|
||||
}
|
||||
|
||||
/// <param name="input"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="ISpeckleGraphQLClient.ExecuteGraphQLRequest{T}"/>
|
||||
public async Task<bool> Cancel(CancelRequestInput input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
//language=graphql
|
||||
const string QUERY = """
|
||||
mutation IngestCancel($projectId: ID!, $input: CancelRequestInput!) {
|
||||
data:projectMutations {
|
||||
data:ingestMutations(projectId: $projectId) {
|
||||
data:cancel(input: $input)
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
GraphQLRequest request = new() { Query = QUERY, Variables = new { input, input.projectId } };
|
||||
|
||||
var res = await _client
|
||||
.ExecuteGraphQLRequest<RequiredResponse<RequiredResponse<RequiredResponse<bool>>>>(request, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return res.data.data.data;
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Speckle.Sdk.Api;
|
||||
using Speckle.Sdk.Api.GraphQL.Inputs;
|
||||
using Speckle.Sdk.Api.GraphQL.Models;
|
||||
using Speckle.Sdk.Api.GraphQL.Resources;
|
||||
using Speckle.Sdk.Host;
|
||||
using Speckle.Sdk.Models;
|
||||
using Speckle.Sdk.Transports;
|
||||
|
||||
namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources;
|
||||
|
||||
public class IngestResourceTests : IAsyncLifetime
|
||||
{
|
||||
private IClient _testUser;
|
||||
private IngestResource Sut => _testUser.Ingest;
|
||||
private Project _project;
|
||||
private Model _model;
|
||||
private IOperations _operations;
|
||||
|
||||
public Task DisposeAsync() => Task.CompletedTask;
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
TypeLoader.Reset();
|
||||
TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly());
|
||||
var serviceProvider = TestServiceSetup.GetServiceProvider();
|
||||
_operations = serviceProvider.GetRequiredService<IOperations>();
|
||||
|
||||
_testUser = await Fixtures.SeedUserWithClient();
|
||||
_project = await _testUser.Project.Create(new("Test project", "", null));
|
||||
_model = await _testUser.Model.Create(new("Test Model 1", "", _project.id));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAndError()
|
||||
{
|
||||
var input = new IngestCreateInput(
|
||||
"myTestFile",
|
||||
1,
|
||||
_model.id,
|
||||
_project.id,
|
||||
".NET",
|
||||
"0.0.0",
|
||||
new Dictionary<string, object?>()
|
||||
);
|
||||
Ingest ingest = await Sut.Create(input);
|
||||
|
||||
var errorInput = new IngestErrorInput("A bad thing happened", "Over hear!", ingest.id, _project.id);
|
||||
var res = await Sut.Error(errorInput);
|
||||
Assert.True(res);
|
||||
|
||||
var result = await Sut.GetIngests(_model.id, _project.id);
|
||||
|
||||
await Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAndCancel()
|
||||
{
|
||||
var input = new IngestCreateInput(
|
||||
"myTestFile",
|
||||
1,
|
||||
_model.id,
|
||||
_project.id,
|
||||
".NET",
|
||||
"0.0.0",
|
||||
new Dictionary<string, object?>()
|
||||
);
|
||||
Ingest ingest = await Sut.Create(input);
|
||||
|
||||
var errorInput = new CancelRequestInput(ingest.id, _project.id);
|
||||
var res = await Sut.Cancel(errorInput);
|
||||
Assert.True(res);
|
||||
|
||||
var result = await Sut.GetIngests(_model.id, _project.id);
|
||||
|
||||
await Verify(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAndEnd()
|
||||
{
|
||||
var create = new IngestCreateInput(
|
||||
"myTestFile",
|
||||
1,
|
||||
_model.id,
|
||||
_project.id,
|
||||
".NET",
|
||||
"0.0.0",
|
||||
new Dictionary<string, object?>()
|
||||
);
|
||||
Ingest ingest = await Sut.Create(create);
|
||||
|
||||
var myObject = Fixtures.GenerateNestedObject();
|
||||
var sendResult = await _operations.Send2(
|
||||
_testUser.ServerUrl,
|
||||
_project.id,
|
||||
_testUser.Account.token,
|
||||
myObject,
|
||||
new Progress<ProgressArgs>(x =>
|
||||
{
|
||||
var updateInput = new IngestUpdateInput(
|
||||
ingest.id,
|
||||
x.Total == null ? null : x.Count / x.Total,
|
||||
$"{x.Count} / {x.Total}",
|
||||
_project.id
|
||||
);
|
||||
_ = Sut.Update(updateInput).Result;
|
||||
}),
|
||||
CancellationToken.None,
|
||||
new(true, true)
|
||||
);
|
||||
|
||||
var finish = new IngestFinishInput(ingest.id, "Yay! we completed", sendResult.RootId, _project.id);
|
||||
var res = await Sut.End(finish);
|
||||
Assert.NotNull(res);
|
||||
|
||||
var result = await Sut.GetIngests(_model.id, _project.id);
|
||||
await Verify(result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user