diff --git a/CLAUDE.md b/CLAUDE.md index e12cf07c..ab8f6c6d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -80,6 +80,15 @@ dotnet test src/Weaviate.Client.Tests --filter "FullyQualifiedName~Integration" ./ci/stop_weaviate.sh 1.36.9 # stop when done ``` +## REST DTO Generation + +`src/Weaviate.Client/Rest/Dto/Models.g.cs` is **auto-generated** — never edit it manually. To update it: + +1. Run `./tools/openapi_sync.sh` followed by the desired branch or tag to target from the github.com/weaviate/weaviate repo +2. Run `./tools/gen_rest_dto.sh` to regenerate `Models.g.cs` via NSwag + +To customize the generated output (e.g., access modifiers), edit the Liquid templates in `src/Weaviate.Client/Rest/Schema/Templates/`. These override NSwag's built-in templates. `File.liquid` overrides the file-level template (controls `FileResponse` visibility, etc.). + ## Public API Tracking After adding public types/members, run: diff --git a/ci/docker-compose.yml b/ci/docker-compose.yml index a04ddba5..7a57427e 100644 --- a/ci/docker-compose.yml +++ b/ci/docker-compose.yml @@ -24,6 +24,8 @@ services: PERSISTENCE_DATA_PATH: '/var/lib/weaviate' ENABLE_MODULES: text2vec-transformers,text2vec-cohere,backup-filesystem,generative-dummy,generative-anyscale,reranker-dummy,reranker-cohere,text2vec-ollama,generative-ollama BACKUP_FILESYSTEM_PATH: "/tmp/backups" + EXPORT_ENABLED: 'true' + EXPORT_DEFAULT_PATH: "/tmp/exports" CLUSTER_GOSSIP_BIND_PORT: "7100" CLUSTER_DATA_BIND_PORT: "7101" CLUSTER_HOSTNAME: "singlenode" diff --git a/docs/BATCH_API_USAGE.md b/docs/BATCH_API_USAGE.md index 74323f22..1eb14bb5 100644 --- a/docs/BATCH_API_USAGE.md +++ b/docs/BATCH_API_USAGE.md @@ -219,7 +219,6 @@ The `BatchContext.State` property indicates the current state: - `Open` - Batch is accepting objects - `InFlight` - Processing in progress - `Closed` - Batch completed normally -- `Aborted` - Batch failed with error ## Reference Batching diff --git a/src/Weaviate.Client.Tests/Integration/TestExports.cs b/src/Weaviate.Client.Tests/Integration/TestExports.cs new file mode 100644 index 00000000..f9c8e256 --- /dev/null +++ b/src/Weaviate.Client.Tests/Integration/TestExports.cs @@ -0,0 +1,131 @@ +namespace Weaviate.Client.Tests.Integration; + +using Weaviate.Client.Models; + +/// +/// Integration tests for ExportClient. +/// Requires Weaviate 1.37.0+ with export support enabled. +/// +[Trait("Category", "Slow")] +[Collection("TestExports")] +[CollectionDefinition("TestExports", DisableParallelization = true)] +public class TestExports : IntegrationTests +{ + static readonly BackupBackend _backend = new FilesystemBackend(); + + public override async ValueTask InitializeAsync() + { + await base.InitializeAsync(); + + RequireVersion("1.37.0"); + } + + [Fact] + public async Task CreateSync_CompletesSuccessfully() + { + var ct = TestContext.Current.CancellationToken; + var collection = await CollectionFactory("ExportTest1"); + + var export = await _weaviate.Export.CreateSync( + new ExportCreateRequest( + $"export-sync-{Guid.NewGuid():N}", + _backend, + IncludeCollections: [collection.Name] + ), + timeout: TimeSpan.FromMinutes(2), + cancellationToken: ct + ); + + Assert.Equal(ExportStatus.Success, export.Status); + Assert.NotNull(export.CompletedAt); + } + + [Fact] + public async Task Create_ThenWaitForCompletion() + { + var ct = TestContext.Current.CancellationToken; + var collection = await CollectionFactory("ExportTest2"); + + await using var operation = await _weaviate.Export.Create( + new ExportCreateRequest( + $"export-async-{Guid.NewGuid():N}", + _backend, + IncludeCollections: [collection.Name] + ), + ct + ); + + Assert.NotNull(operation.Current); + + var result = await operation.WaitForCompletion(TimeSpan.FromMinutes(2), ct); + + Assert.Equal(ExportStatus.Success, result.Status); + Assert.True(operation.IsCompleted); + Assert.True(operation.IsSuccessful); + } + + [Fact] + public async Task GetStatus_ReturnsExportInfo() + { + var ct = TestContext.Current.CancellationToken; + var collection = await CollectionFactory("ExportTest3"); + var exportId = $"export-status-{Guid.NewGuid():N}"; + + await _weaviate.Export.CreateSync( + new ExportCreateRequest(exportId, _backend, IncludeCollections: [collection.Name]), + timeout: TimeSpan.FromMinutes(2), + cancellationToken: ct + ); + + var status = await _weaviate.Export.GetStatus(_backend, exportId, ct); + + Assert.Equal(exportId, status.Id); + Assert.Equal(ExportStatus.Success, status.Status); + } + + [Fact] + public async Task Cancel_StopsRunningExport() + { + var ct = TestContext.Current.CancellationToken; + var collection = await CollectionFactory("ExportTest4"); + + await using var operation = await _weaviate.Export.Create( + new ExportCreateRequest( + $"export-cancel-{Guid.NewGuid():N}", + _backend, + IncludeCollections: [collection.Name] + ), + ct + ); + + // Cancel immediately — may already have completed for small collections. + // Server responds with 409 Conflict when the export has already finished, + // or 404 Not Found if the record is no longer available. + try + { + await _weaviate.Export.Cancel(_backend, operation.Current.Id, ct); + } + catch (WeaviateConflictException) + { + // Export already finished — can't cancel a terminal export. + } + catch (WeaviateNotFoundException) + { + // Export record no longer available. + } + + try + { + var status = await _weaviate.Export.GetStatus(_backend, operation.Current.Id, ct); + + Assert.True( + status.Status is ExportStatus.Canceled or ExportStatus.Success, + $"Expected Canceled or Success but got {status.Status}" + ); + } + catch (WeaviateNotFoundException) + { + // Treat vanished export as successfully canceled. + } + } +} diff --git a/src/Weaviate.Client.Tests/Integration/TestReplication.cs b/src/Weaviate.Client.Tests/Integration/TestReplication.cs index f85c28c1..c83957bb 100644 --- a/src/Weaviate.Client.Tests/Integration/TestReplication.cs +++ b/src/Weaviate.Client.Tests/Integration/TestReplication.cs @@ -490,7 +490,8 @@ await op1.WaitForCompletion( { await _weaviate.Cluster.Replications.DeleteAll(TestContext.Current.CancellationToken); - // Poll up to 30s for asynchronous deletion to take effect. + // Poll up to 30s for asynchronous deletion to take effect. Operations flagged + // ScheduledForDelete count as deleted — the server clears them on its own cadence. for (int i = 0; i < 60; i++) { var operations = await _weaviate.Cluster.Replications.ListAll( @@ -499,7 +500,7 @@ await op1.WaitForCompletion( Trace.WriteLine( $"Attempt {attempt + 1}, poll {i}: remaining operations: {operations.Count()}" ); - if (!operations.Any()) + if (!operations.Any(o => o.ScheduledForDelete != true)) { allDeleted = true; break; diff --git a/src/Weaviate.Client.Tests/Unit/TestExportClient.cs b/src/Weaviate.Client.Tests/Unit/TestExportClient.cs new file mode 100644 index 00000000..fefba84a --- /dev/null +++ b/src/Weaviate.Client.Tests/Unit/TestExportClient.cs @@ -0,0 +1,272 @@ +using System.Net; +using Weaviate.Client.Models; +using Weaviate.Client.Tests.Unit.Mocks; + +namespace Weaviate.Client.Tests.Unit; + +/// +/// Unit tests for ExportClient, focusing on HTTP request routing and DTO-to-model mapping. +/// +public class TestExportClient +{ + /// + /// Create must issue a POST to /v1/export/filesystem with the correct JSON body. + /// + [Fact] + public async Task Create_SendsPostToExportEndpoint() + { + var json = """ + { + "id": "my-export", + "backend": "filesystem", + "status": "STARTED", + "classes": ["Article"] + } + """; + + var (client, handler) = MockWeaviateClient.CreateWithMockHandler( + syncHandler: _ => new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"), + }, + serverVersion: "1.37.0" + ); + + await using var operation = await client.Export.Create( + new ExportCreateRequest("my-export", new FilesystemBackend()), + TestContext.Current.CancellationToken + ); + + Assert.NotNull(handler.LastRequest); + handler + .LastRequest!.ShouldHaveMethod(HttpMethod.Post) + .ShouldHavePath("/v1/export/filesystem"); + } + + /// + /// GetStatus must issue a GET to /v1/export/filesystem/{id}. + /// + [Fact] + public async Task GetStatus_SendsGetToStatusEndpoint() + { + var json = """ + { + "id": "my-export", + "backend": "filesystem", + "status": "SUCCESS", + "startedAt": "2026-01-01T00:00:00Z", + "completedAt": "2026-01-01T00:01:00Z", + "tookInMs": 60000 + } + """; + + var (client, handler) = MockWeaviateClient.CreateWithMockHandler( + syncHandler: _ => new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"), + }, + serverVersion: "1.37.0" + ); + + var export = await client.Export.GetStatus( + new FilesystemBackend(), + "my-export", + TestContext.Current.CancellationToken + ); + + Assert.NotNull(handler.LastRequest); + handler + .LastRequest!.ShouldHaveMethod(HttpMethod.Get) + .ShouldHavePath("/v1/export/filesystem/my-export"); + + Assert.Equal("my-export", export.Id); + Assert.Equal(ExportStatus.Success, export.Status); + Assert.Equal(60000, export.TookInMs); + } + + /// + /// Cancel must issue a DELETE to /v1/export/filesystem/{id}. + /// + [Fact] + public async Task Cancel_SendsDeleteToExportEndpoint() + { + var (client, handler) = MockWeaviateClient.CreateWithMockHandler( + syncHandler: _ => new HttpResponseMessage(HttpStatusCode.NoContent), + serverVersion: "1.37.0" + ); + + await client.Export.Cancel( + new FilesystemBackend(), + "my-export", + TestContext.Current.CancellationToken + ); + + Assert.NotNull(handler.LastRequest); + handler + .LastRequest!.ShouldHaveMethod(HttpMethod.Delete) + .ShouldHavePath("/v1/export/filesystem/my-export"); + } + + /// + /// Status parsing should correctly map all known status strings. + /// + [Theory] + [InlineData("STARTED", ExportStatus.Started)] + [InlineData("TRANSFERRING", ExportStatus.Transferring)] + [InlineData("SUCCESS", ExportStatus.Success)] + [InlineData("FAILED", ExportStatus.Failed)] + [InlineData("CANCELED", ExportStatus.Canceled)] + public async Task GetStatus_ParsesStatusCorrectly(string statusString, ExportStatus expected) + { + var json = $$""" + { + "id": "my-export", + "backend": "filesystem", + "status": "{{statusString}}" + } + """; + + var (client, _) = MockWeaviateClient.CreateWithMockHandler( + syncHandler: _ => new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"), + }, + serverVersion: "1.37.0" + ); + + var export = await client.Export.GetStatus( + new FilesystemBackend(), + "my-export", + TestContext.Current.CancellationToken + ); + + Assert.Equal(expected, export.Status); + } + + /// + /// GetStatus should correctly deserialize shard progress from the response. + /// + [Fact] + public async Task GetStatus_DeserializesShardStatus() + { + var json = """ + { + "id": "my-export", + "backend": "filesystem", + "status": "TRANSFERRING", + "shardStatus": { + "Article": { + "shard0": { + "status": "TRANSFERRING", + "objectsExported": 42 + }, + "shard1": { + "status": "SUCCESS", + "objectsExported": 100 + } + } + } + } + """; + + var (client, _) = MockWeaviateClient.CreateWithMockHandler( + syncHandler: _ => new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"), + }, + serverVersion: "1.37.0" + ); + + var export = await client.Export.GetStatus( + new FilesystemBackend(), + "my-export", + TestContext.Current.CancellationToken + ); + + Assert.NotNull(export.ShardStatus); + Assert.True(export.ShardStatus!.ContainsKey("Article")); + var articleShards = export.ShardStatus["Article"]; + Assert.Equal(2, articleShards.Count); + Assert.Equal(42, articleShards["shard0"].ObjectsExported); + Assert.Equal(100, articleShards["shard1"].ObjectsExported); + } + + /// + /// Create with include/exclude collections should send the correct JSON body. + /// + [Fact] + public async Task Create_WithIncludeCollections_SendsCorrectBody() + { + var json = """ + { + "id": "my-export", + "backend": "filesystem", + "status": "STARTED", + "classes": ["Article"] + } + """; + + string? requestBody = null; + var (client, _) = MockWeaviateClient.CreateWithMockHandler( + handlerWithToken: async (req, ct) => + { + if (req.Method == HttpMethod.Post) + { + requestBody = await req.Content!.ReadAsStringAsync(ct); + } + return new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent( + json, + System.Text.Encoding.UTF8, + "application/json" + ), + }; + }, + serverVersion: "1.37.0" + ); + + await using var operation = await client.Export.Create( + new ExportCreateRequest( + "my-export", + new FilesystemBackend(), + IncludeCollections: ["Article", "Author"] + ), + TestContext.Current.CancellationToken + ); + + Assert.NotNull(requestBody); + Assert.Contains("\"include\":[\"Article\",\"Author\"]", requestBody); + } + + /// + /// Create with S3 backend uses correct endpoint path. + /// + [Fact] + public async Task Create_WithS3Backend_UsesCorrectEndpoint() + { + var json = """ + { + "id": "my-export", + "backend": "s3", + "status": "STARTED" + } + """; + + var (client, handler) = MockWeaviateClient.CreateWithMockHandler( + syncHandler: _ => new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"), + }, + serverVersion: "1.37.0" + ); + + await using var operation = await client.Export.Create( + new ExportCreateRequest("my-export", ObjectStorageBackend.S3()), + TestContext.Current.CancellationToken + ); + + Assert.NotNull(handler.LastRequest); + handler.LastRequest!.ShouldHaveMethod(HttpMethod.Post).ShouldHavePath("/v1/export/s3"); + } +} diff --git a/src/Weaviate.Client.VectorData/PublicAPI.Unshipped.txt b/src/Weaviate.Client.VectorData/PublicAPI.Unshipped.txt index cfc72837..cf2f821d 100644 --- a/src/Weaviate.Client.VectorData/PublicAPI.Unshipped.txt +++ b/src/Weaviate.Client.VectorData/PublicAPI.Unshipped.txt @@ -3,6 +3,7 @@ Weaviate.Client.VectorData.DependencyInjection.WeaviateVectorDataServiceCollecti Weaviate.Client.VectorData.WeaviateVectorStore Weaviate.Client.VectorData.WeaviateVectorStore.WeaviateVectorStore(Weaviate.Client.WeaviateClient! client, Weaviate.Client.VectorData.WeaviateVectorStoreOptions? options = null) -> void Weaviate.Client.VectorData.WeaviateVectorStoreCollection +Weaviate.Client.VectorData.WeaviateVectorStoreCollection.HybridSearchAsync(TInput searchValue, System.Collections.Generic.ICollection! keywords, int top, Microsoft.Extensions.VectorData.HybridSearchOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IAsyncEnumerable!>! Weaviate.Client.VectorData.WeaviateVectorStoreCollection.WeaviateVectorStoreCollection(Weaviate.Client.WeaviateClient! client, string! name, Microsoft.Extensions.VectorData.VectorStoreCollectionDefinition? definition = null, Weaviate.Client.VectorData.WeaviateVectorStoreCollectionOptions? options = null) -> void Weaviate.Client.VectorData.WeaviateVectorStoreCollectionOptions Weaviate.Client.VectorData.WeaviateVectorStoreCollectionOptions.ConsistencyLevel.get -> Weaviate.Client.ConsistencyLevels? diff --git a/src/Weaviate.Client.VectorData/WeaviateVectorStoreCollection.cs b/src/Weaviate.Client.VectorData/WeaviateVectorStoreCollection.cs index beb21bb3..b009f8b1 100644 --- a/src/Weaviate.Client.VectorData/WeaviateVectorStoreCollection.cs +++ b/src/Weaviate.Client.VectorData/WeaviateVectorStoreCollection.cs @@ -297,7 +297,7 @@ public override async IAsyncEnumerable> SearchAsync< } /// - public new async IAsyncEnumerable> HybridSearchAsync( + public async IAsyncEnumerable> HybridSearchAsync( TInput searchValue, ICollection keywords, int top, diff --git a/src/Weaviate.Client/Batch/README.md b/src/Weaviate.Client/Batch/README.md index fdcbfd3d..81245dbf 100644 --- a/src/Weaviate.Client/Batch/README.md +++ b/src/Weaviate.Client/Batch/README.md @@ -30,7 +30,7 @@ Manages the lifecycle and state of a batch, including adding objects, retrying, - `Close(CancellationToken)` - Close the batch and wait for all results **Properties:** -- `State` - Current `BatchState` (Open, InFlight, Closed, Aborted) +- `State` - Current `BatchState` (Open, InFlight, Closed) ### `TaskHandle` diff --git a/src/Weaviate.Client/Enums.cs b/src/Weaviate.Client/Enums.cs index f158c4d4..482b6bf8 100644 --- a/src/Weaviate.Client/Enums.cs +++ b/src/Weaviate.Client/Enums.cs @@ -41,6 +41,11 @@ public enum ResourceType /// Backup, + /// + /// The export resource type + /// + Export, + /// /// The group resource type /// diff --git a/src/Weaviate.Client/ExportClient.cs b/src/Weaviate.Client/ExportClient.cs new file mode 100644 index 00000000..6a759b1f --- /dev/null +++ b/src/Weaviate.Client/ExportClient.cs @@ -0,0 +1,183 @@ +using Weaviate.Client.Models; + +namespace Weaviate.Client; + +/// +/// Adds export property to WeaviateClient +/// +public partial class WeaviateClient +{ + private ExportClient? _exports; + + /// + /// A client for managing collection exports. + /// + public ExportClient Export => _exports ??= new(this); +} + +/// +/// Provides export operations for Weaviate collections — creation, status tracking, and cancellation. +/// +public class ExportClient +{ + private readonly WeaviateClient _client; + + /// + /// Static configuration used for all export operations. + /// + public static ExportClientConfig Config { get; set; } = ExportClientConfig.Default; + + internal ExportClient(WeaviateClient client) + { + _client = client; + } + + /// + /// Start creating an export asynchronously. + /// Returns an ExportOperation that can be used to track status or wait for completion. + /// + [RequiresWeaviateVersion(1, 37, 0)] + public async Task Create( + ExportCreateRequest request, + CancellationToken cancellationToken = default + ) + { + await _client.EnsureVersion(); + + var restRequest = BuildExportCreateRequest(request); + var response = await _client.RestClient.ExportCreate( + request.Backend.Provider, + restRequest, + cancellationToken + ); + var model = ToModel(response); + + return new ExportOperation( + model, + async (ct) => await GetStatus(request.Backend, model.Id, ct), + async (ct) => await Cancel(request.Backend, model.Id, ct) + ); + } + + /// + /// Create an export and wait synchronously for completion. + /// + [RequiresWeaviateVersion(1, 37, 0)] + public async Task CreateSync( + ExportCreateRequest request, + TimeSpan? timeout = null, + CancellationToken cancellationToken = default + ) + { + await _client.EnsureVersion(); + var operation = await Create(request, cancellationToken); + return await operation.WaitForCompletion(timeout, cancellationToken); + } + + /// + /// Get status for an export + /// + [RequiresWeaviateVersion(1, 37, 0)] + public async Task GetStatus( + BackupBackend backend, + string id, + CancellationToken cancellationToken = default + ) + { + await _client.EnsureVersion(); + + var status = await _client.RestClient.ExportGetStatus( + backend.Provider, + id, + cancellationToken + ); + return ToModel(status, backend); + } + + /// + /// Cancel a running export + /// + [RequiresWeaviateVersion(1, 37, 0)] + public async Task Cancel( + BackupBackend backend, + string id, + CancellationToken cancellationToken = default + ) + { + await _client.EnsureVersion(); + + await _client.RestClient.ExportCancel(backend.Provider, id, cancellationToken); + } + + private static Rest.Dto.ExportCreateRequest BuildExportCreateRequest( + ExportCreateRequest request + ) + { + return new Rest.Dto.ExportCreateRequest + { + Id = request.Id, + File_format = request.FileFormat switch + { + ExportFileFormat.Parquet => Rest.Dto.ExportCreateRequestFile_format.Parquet, + _ => Rest.Dto.ExportCreateRequestFile_format.Parquet, + }, + Include = request.IncludeCollections?.ToList(), + Exclude = request.ExcludeCollections?.ToList(), + }; + } + + private static Export ToModel(Rest.Dto.ExportCreateResponse dto) => + new( + dto.Id ?? string.Empty, + ParseBackend(dto.Backend), + dto.Path, + dto.Status?.ToString() ?? string.Empty, + dto.Classes?.ToArray(), + dto.StartedAt, + null, + null + ); + + private static Export ToModel(Rest.Dto.ExportStatusResponse dto, BackupBackend backend) => + new( + dto.Id ?? string.Empty, + backend, + dto.Path, + dto.Status?.ToString() ?? string.Empty, + dto.Classes?.ToArray(), + dto.StartedAt, + dto.CompletedAt, + dto.Error + ) + { + ShardStatus = dto.ShardStatus?.ToDictionary( + kvp => kvp.Key, + kvp => + kvp.Value.ToDictionary( + inner => inner.Key, + inner => new ShardProgress( + inner.Value.Status?.ToString() ?? string.Empty, + (int)(inner.Value.ObjectsExported ?? 0), + inner.Value.Error, + inner.Value.SkipReason + ) + ) + ), + TookInMs = dto.TookInMs.HasValue ? (int)dto.TookInMs.Value : null, + }; + + private static BackupBackend ParseBackend(string? backendStr) + { + var provider = backendStr?.ToLowerInvariant() switch + { + "filesystem" => BackupStorageProvider.Filesystem, + "s3" => BackupStorageProvider.S3, + "gcs" => BackupStorageProvider.GCS, + "azure" => BackupStorageProvider.Azure, + _ => BackupStorageProvider.None, + }; + return provider == BackupStorageProvider.None ? BackupBackend.Empty() + : provider == BackupStorageProvider.Filesystem ? new FilesystemBackend() + : new ObjectStorageBackend(provider); + } +} diff --git a/src/Weaviate.Client/Models/BackupOperationBase.cs b/src/Weaviate.Client/Models/BackupOperationBase.cs index db47f420..ff1d64b3 100644 --- a/src/Weaviate.Client/Models/BackupOperationBase.cs +++ b/src/Weaviate.Client/Models/BackupOperationBase.cs @@ -34,17 +34,17 @@ public abstract class BackupOperationBase : IDisposable, IAsyncDisposable /// /// The is completed /// - private bool _isCompleted; + private volatile bool _isCompleted; /// /// The is successful /// - private bool _isSuccessful; + private volatile bool _isSuccessful; /// /// The is canceled /// - private bool _isCanceled; + private volatile bool _isCanceled; /// /// The disposed @@ -97,6 +97,8 @@ Func operationCancel /// private Task StartBackgroundRefresh() { + if (_isCompleted) + return Task.CompletedTask; return Task.Run(async () => { while (!_isCompleted && !_cts.IsCancellationRequested) @@ -110,10 +112,7 @@ private Task StartBackgroundRefresh() { break; } - catch - { - // Swallow errors, optionally log - } + catch { } } }); } @@ -135,10 +134,7 @@ private async Task RefreshStatusInternal(CancellationToken cancellationToken = d _isCompleted = true; _isSuccessful = status.Status == BackupStatus.Success; _isCanceled = status.Status == BackupStatus.Canceled; - await _cts.CancelAsync(); // Stop background polling - - // Auto-dispose resources now that operation is complete - // This prevents resource leaks if caller forgets to dispose + await _cts.CancelAsync(); DisposeInternal(); } } @@ -157,13 +153,14 @@ public async Task WaitForCompletion( var effectiveTimeout = timeout ?? BackupClient.Config.Timeout; var start = DateTime.UtcNow; - var effectiveToken = CancellationTokenSource - .CreateLinkedTokenSource(_cts.Token, cancellationToken) - .Token; + using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource( + _cts.Token, + cancellationToken + ); + var effectiveToken = linkedCts.Token; while (!_isCompleted && !effectiveToken.IsCancellationRequested) { - effectiveToken.ThrowIfCancellationRequested(); if (DateTime.UtcNow - start > effectiveTimeout) { throw new TimeoutException( @@ -174,10 +171,7 @@ public async Task WaitForCompletion( { await Task.Delay(BackupClient.Config.PollInterval, effectiveToken); } - catch (OperationCanceledException) when (_isCompleted) - { - // Operation completed while waiting - } + catch (OperationCanceledException) when (_isCompleted) { } } return _current; } @@ -187,7 +181,6 @@ public async Task WaitForCompletion( /// public async Task Cancel(CancellationToken cancellationToken = default) { - // Call server-side Cancel await _operationCancel(cancellationToken); await RefreshStatusInternal(cancellationToken); @@ -207,10 +200,7 @@ protected virtual void Dispose(bool disposing) { _backgroundRefreshTask.Wait(BackupClient.Config.PollInterval); } - catch (Exception) - { - // Ignore exceptions from waiting on background task, as disposal is best-effort - } + catch (Exception) { } _cts.Dispose(); } _disposed = true; @@ -226,13 +216,9 @@ private void DisposeInternal() try { - // Wait for background task to complete (should be immediate since we just canceled) _backgroundRefreshTask.Wait(BackupClient.Config.PollInterval); } - catch (Exception) - { - // Ignore exceptions, disposal is best-effort - } + catch (Exception) { } _cts.Dispose(); _disposed = true; @@ -258,13 +244,9 @@ public async ValueTask DisposeAsync() try { - // Await the background task gracefully await _backgroundRefreshTask.ConfigureAwait(false); } - catch (Exception) - { - // Ignore exceptions, disposal is best-effort - } + catch (Exception) { } _cts.Dispose(); _disposed = true; diff --git a/src/Weaviate.Client/Models/Export.cs b/src/Weaviate.Client/Models/Export.cs new file mode 100644 index 00000000..6c0547c6 --- /dev/null +++ b/src/Weaviate.Client/Models/Export.cs @@ -0,0 +1,126 @@ +using Weaviate.Client.Internal; + +namespace Weaviate.Client.Models; + +/// +/// Specifies the file format for export operations. +/// +public enum ExportFileFormat +{ + /// + /// Apache Parquet format + /// + [System.Text.Json.Serialization.JsonStringEnumMemberName("parquet")] + Parquet, +} + +/// +/// Represents the status of an export operation. +/// +public enum ExportStatus +{ + /// + /// The status is unknown. + /// + Unknown, + + /// + /// The export has started. + /// + Started, + + /// + /// The export is transferring data. + /// + Transferring, + + /// + /// The export completed successfully. + /// + Success, + + /// + /// The export failed. + /// + Failed, + + /// + /// The export was canceled. + /// + Canceled, +} + +/// +/// Provides extension methods for parsing values from strings. +/// +public static class ExportStatusExtensions +{ + /// + /// Converts a string status to an value. + /// + /// The status string to parse. + /// The parsed value. + public static ExportStatus ToExportStatus(this string? status) + { + return status?.ToUpperInvariant() switch + { + "STARTED" => ExportStatus.Started, + "TRANSFERRING" => ExportStatus.Transferring, + "SUCCESS" => ExportStatus.Success, + "FAILED" => ExportStatus.Failed, + "CANCELED" => ExportStatus.Canceled, + _ => ExportStatus.Unknown, + }; + } +} + +/// +/// Represents an export as returned by create/status operations. +/// +public record Export( + string Id, + BackupBackend Backend, + string? Path, + string StatusRaw, + string[]? Collections, + DateTimeOffset? StartedAt, + DateTimeOffset? CompletedAt, + string? Error +) +{ + /// + /// Parsed export status + /// + public ExportStatus Status => StatusRaw.ToExportStatus(); + + /// + /// Per-shard export progress. Outer key is collection, inner key is shard name. + /// + public Dictionary>? ShardStatus { get; init; } + + /// + /// Time taken in milliseconds, available after completion. + /// + public int? TookInMs { get; init; } +} + +/// +/// Represents the progress of a single shard export. +/// +public record ShardProgress( + string StatusRaw, + int ObjectsExported, + string? Error, + string? SkipReason +); + +/// +/// Represents the options for creating an export operation. +/// +public record ExportCreateRequest( + string Id, + BackupBackend Backend, + ExportFileFormat FileFormat = ExportFileFormat.Parquet, + AutoArray? IncludeCollections = null, + AutoArray? ExcludeCollections = null +); diff --git a/src/Weaviate.Client/Models/ExportClientConfig.cs b/src/Weaviate.Client/Models/ExportClientConfig.cs new file mode 100644 index 00000000..ba65ea01 --- /dev/null +++ b/src/Weaviate.Client/Models/ExportClientConfig.cs @@ -0,0 +1,24 @@ +namespace Weaviate.Client.Models; + +/// +/// Configuration for export client operations (polling interval, timeout). +/// +public record ExportClientConfig +{ + /// + /// Default polling interval for checking export status. + /// Default: 250ms + /// + public TimeSpan PollInterval { get; init; } = TimeSpan.FromMilliseconds(250); + + /// + /// Default timeout for waiting for completion of export operations. + /// Default: 10 minutes + /// + public TimeSpan Timeout { get; init; } = TimeSpan.FromMinutes(10); + + /// + /// Default configuration instance. + /// + public static ExportClientConfig Default { get; } = new(); +} diff --git a/src/Weaviate.Client/Models/ExportOperation.cs b/src/Weaviate.Client/Models/ExportOperation.cs new file mode 100644 index 00000000..c3df2d85 --- /dev/null +++ b/src/Weaviate.Client/Models/ExportOperation.cs @@ -0,0 +1,14 @@ +namespace Weaviate.Client.Models; + +/// +/// Represents a running export operation with status tracking and cancellation. +/// +public class ExportOperation : ExportOperationBase +{ + internal ExportOperation( + Export initial, + Func> statusFetcher, + Func operationCancel + ) + : base(initial, statusFetcher, operationCancel) { } +} diff --git a/src/Weaviate.Client/Models/ExportOperationBase.cs b/src/Weaviate.Client/Models/ExportOperationBase.cs new file mode 100644 index 00000000..f38c7b3a --- /dev/null +++ b/src/Weaviate.Client/Models/ExportOperationBase.cs @@ -0,0 +1,215 @@ +namespace Weaviate.Client.Models; + +/// +/// Abstract base class for export operations, providing status polling, cancellation, and resource management. +/// +public abstract class ExportOperationBase : IDisposable, IAsyncDisposable +{ + private readonly Func> _statusFetcher; + private readonly Func _operationCancel; + private readonly CancellationTokenSource _cts = new(); + private readonly Task _backgroundRefreshTask; + private Export _current; + private volatile bool _isCompleted; + private volatile bool _isSuccessful; + private volatile bool _isCanceled; + private bool _disposed; + + /// + /// Initializes a new instance of the class. + /// + /// The initial export state. + /// A delegate to fetch the latest export status. + /// A delegate to cancel the export operation. + protected ExportOperationBase( + Export initial, + Func> statusFetcher, + Func operationCancel + ) + { + _current = initial; + _statusFetcher = statusFetcher; + _operationCancel = operationCancel; + _isCompleted = IsTerminalStatus(initial.Status); + _isSuccessful = initial.Status == ExportStatus.Success; + _isCanceled = initial.Status == ExportStatus.Canceled; + _backgroundRefreshTask = StartBackgroundRefresh(); + } + + /// + /// Gets the current export status and metadata. + /// + public Export Current => _current; + + /// + /// Gets a value indicating whether the export operation has completed (success, failure, or canceled). + /// + public bool IsCompleted => _isCompleted; + + /// + /// Gets a value indicating whether the export operation completed successfully. + /// + public bool IsSuccessful => _isSuccessful; + + /// + /// Gets a value indicating whether the export operation was canceled. + /// + public bool IsCanceled => _isCanceled; + + private Task StartBackgroundRefresh() + { + if (_isCompleted) + return Task.CompletedTask; + return Task.Run(async () => + { + while (!_isCompleted && !_cts.IsCancellationRequested) + { + try + { + await Task.Delay(ExportClient.Config.PollInterval, _cts.Token); + await RefreshStatusInternal(); + } + catch (OperationCanceledException) + { + break; + } + catch { } + } + }); + } + + private async Task RefreshStatusInternal(CancellationToken cancellationToken = default) + { + if (_isCompleted) + return; + var status = await _statusFetcher( + cancellationToken == default ? _cts.Token : cancellationToken + ); + _current = status; + if (IsTerminalStatus(status.Status)) + { + _isCompleted = true; + _isSuccessful = status.Status == ExportStatus.Success; + _isCanceled = status.Status == ExportStatus.Canceled; + await _cts.CancelAsync(); + DisposeInternal(); + } + } + + /// + /// Waits asynchronously for the export operation to complete or timeout. + /// + /// Optional timeout for the operation. If not specified, uses the default export timeout. + /// A cancellation token to observe while waiting. + /// The final result. + public async Task WaitForCompletion( + TimeSpan? timeout = null, + CancellationToken cancellationToken = default + ) + { + var effectiveTimeout = timeout ?? ExportClient.Config.Timeout; + var start = DateTime.UtcNow; + + using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource( + _cts.Token, + cancellationToken + ); + var effectiveToken = linkedCts.Token; + + while (!_isCompleted && !effectiveToken.IsCancellationRequested) + { + if (DateTime.UtcNow - start > effectiveTimeout) + { + throw new TimeoutException( + $"Export operation did not complete within {effectiveTimeout} (last status={_current.Status})." + ); + } + try + { + await Task.Delay(ExportClient.Config.PollInterval, effectiveToken); + } + catch (OperationCanceledException) when (_isCompleted) { } + } + return _current; + } + + /// + /// Cancels the export operation asynchronously. + /// + /// A cancellation token to observe while canceling. + public async Task Cancel(CancellationToken cancellationToken = default) + { + await _operationCancel(cancellationToken); + await RefreshStatusInternal(cancellationToken); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + if (disposing) + { + _cts.Cancel(); + try + { + _backgroundRefreshTask.Wait(ExportClient.Config.PollInterval); + } + catch (Exception) { } + _cts.Dispose(); + } + _disposed = true; + } + + private void DisposeInternal() + { + if (_disposed) + return; + try + { + _backgroundRefreshTask.Wait(ExportClient.Config.PollInterval); + } + catch (Exception) + { + // Best-effort disposal + } + _cts.Dispose(); + _disposed = true; + } + + /// + /// Disposes the export operation and releases resources. + /// + public void Dispose() + { + Dispose(true); + } + + /// + /// Disposes the export operation asynchronously and releases resources. + /// + /// A representing the asynchronous dispose operation. + public async ValueTask DisposeAsync() + { + if (_disposed) + return; + _cts.Cancel(); + try + { + await _backgroundRefreshTask.ConfigureAwait(false); + } + catch (Exception) + { + // Best-effort disposal + } + _cts.Dispose(); + _disposed = true; + GC.SuppressFinalize(this); + } + + private static bool IsTerminalStatus(ExportStatus? status) + { + return status == ExportStatus.Success + || status == ExportStatus.Failed + || status == ExportStatus.Canceled; + } +} diff --git a/src/Weaviate.Client/PublicAPI.Unshipped.txt b/src/Weaviate.Client/PublicAPI.Unshipped.txt index 0ad485ce..7f542f86 100644 --- a/src/Weaviate.Client/PublicAPI.Unshipped.txt +++ b/src/Weaviate.Client/PublicAPI.Unshipped.txt @@ -424,11 +424,31 @@ override Weaviate.Client.Models.DatabaseUser.ToString() -> string! override Weaviate.Client.Models.DataReference.Equals(object? obj) -> bool override Weaviate.Client.Models.DataReference.GetHashCode() -> int override Weaviate.Client.Models.DataReference.ToString() -> string! +Weaviate.Client.Models.DataReference +Weaviate.Client.Models.DataReference.DataReference(System.Guid From, string! FromProperty, System.Collections.Generic.IEnumerable! To) -> void +Weaviate.Client.Models.DataReference.DataReference(System.Guid from, string! fromProperty, params System.Guid[]! to) -> void +Weaviate.Client.Models.DataReference.DataReference(Weaviate.Client.Models.DataReference! original) -> void +Weaviate.Client.Models.DataReference.Deconstruct(out System.Guid From, out string! FromProperty, out System.Collections.Generic.IEnumerable! To) -> void +Weaviate.Client.Models.DataReference.From.get -> System.Guid +Weaviate.Client.Models.DataReference.From.init -> void +Weaviate.Client.Models.DataReference.FromProperty.get -> string! +Weaviate.Client.Models.DataReference.FromProperty.init -> void +Weaviate.Client.Models.DataReference.To.get -> System.Collections.Generic.IEnumerable! +Weaviate.Client.Models.DataReference.To.init -> void override Weaviate.Client.Models.DataResource.Equals(object? obj) -> bool override Weaviate.Client.Models.DataResource.GetHashCode() -> int override Weaviate.Client.Models.DataResource.ToString() -> string! override Weaviate.Client.Models.EmptyStringEnumConverter.Read(ref System.Text.Json.Utf8JsonReader reader, System.Type! typeToConvert, System.Text.Json.JsonSerializerOptions! options) -> T override Weaviate.Client.Models.EmptyStringEnumConverter.Write(System.Text.Json.Utf8JsonWriter! writer, T value, System.Text.Json.JsonSerializerOptions! options) -> void +override Weaviate.Client.Models.Export.Equals(object? obj) -> bool +override Weaviate.Client.Models.Export.GetHashCode() -> int +override Weaviate.Client.Models.Export.ToString() -> string! +override Weaviate.Client.Models.ExportClientConfig.Equals(object? obj) -> bool +override Weaviate.Client.Models.ExportClientConfig.GetHashCode() -> int +override Weaviate.Client.Models.ExportClientConfig.ToString() -> string! +override Weaviate.Client.Models.ExportCreateRequest.Equals(object? obj) -> bool +override Weaviate.Client.Models.ExportCreateRequest.GetHashCode() -> int +override Weaviate.Client.Models.ExportCreateRequest.ToString() -> string! override Weaviate.Client.Models.FilesystemBackend.$() -> Weaviate.Client.Models.FilesystemBackend! override Weaviate.Client.Models.FilesystemBackend.EqualityContract.get -> System.Type! override Weaviate.Client.Models.FilesystemBackend.Equals(object? obj) -> bool @@ -674,6 +694,8 @@ override Weaviate.Client.Models.GroupByResult.ToString() -> string! override Weaviate.Client.Models.GroupByResult.Equals(object? obj) -> bool override Weaviate.Client.Models.GroupByResult.GetHashCode() -> int override Weaviate.Client.Models.GroupByResult.ToString() -> string! +Weaviate.Client.Models.GroupByResult.QueryProfile.get -> Weaviate.Client.Models.QueryProfile? +Weaviate.Client.Models.GroupByResult.QueryProfile.init -> void override Weaviate.Client.Models.GroupedTask.$() -> Weaviate.Client.Models.GroupedTask! override Weaviate.Client.Models.GroupedTask.EqualityContract.get -> System.Type! override Weaviate.Client.Models.GroupedTask.Equals(object? obj) -> bool @@ -839,6 +861,9 @@ override Weaviate.Client.Models.ShardInfo.ToString() -> string! override Weaviate.Client.Models.ShardingConfig.Equals(object? obj) -> bool override Weaviate.Client.Models.ShardingConfig.GetHashCode() -> int override Weaviate.Client.Models.ShardingConfig.ToString() -> string! +override Weaviate.Client.Models.ShardProgress.Equals(object? obj) -> bool +override Weaviate.Client.Models.ShardProgress.GetHashCode() -> int +override Weaviate.Client.Models.ShardProgress.ToString() -> string! override Weaviate.Client.Models.SimpleTargetVectors.$() -> Weaviate.Client.Models.SimpleTargetVectors! override Weaviate.Client.Models.SimpleTargetVectors.Equals(object? obj) -> bool override Weaviate.Client.Models.SimpleTargetVectors.GetHashCode() -> int @@ -1250,6 +1275,8 @@ override Weaviate.Client.Models.WeaviateResult.ToString() -> string! override Weaviate.Client.Models.WeaviateResult.Equals(object? obj) -> bool override Weaviate.Client.Models.WeaviateResult.GetHashCode() -> int override Weaviate.Client.Models.WeaviateResult.ToString() -> string! +Weaviate.Client.Models.WeaviateResult.QueryProfile.get -> Weaviate.Client.Models.QueryProfile? +Weaviate.Client.Models.WeaviateResult.QueryProfile.init -> void override Weaviate.Client.Models.WeightedField.Equals(object? obj) -> bool override Weaviate.Client.Models.WeightedField.GetHashCode() -> int override Weaviate.Client.Models.WeightedField.ToString() -> string! @@ -1304,6 +1331,8 @@ static Weaviate.Client.Connect.Cloud(string! restEndpoint, string? apiKey = null static Weaviate.Client.Connect.FromEnvironment(string! prefix = "WEAVIATE_", System.TimeSpan? defaultTimeout = null, System.TimeSpan? initTimeout = null, System.TimeSpan? insertTimeout = null, System.TimeSpan? queryTimeout = null) -> System.Threading.Tasks.Task! static Weaviate.Client.Connect.Local(Weaviate.Client.Auth.ApiKeyCredentials! credentials, string! hostname = "localhost", ushort restPort = 8080, ushort grpcPort = 50051, bool useSsl = false, System.Collections.Generic.Dictionary? headers = null, System.Net.Http.HttpMessageHandler? httpMessageHandler = null, System.TimeSpan? defaultTimeout = null, System.TimeSpan? initTimeout = null, System.TimeSpan? insertTimeout = null, System.TimeSpan? queryTimeout = null) -> System.Threading.Tasks.Task! static Weaviate.Client.Connect.Local(Weaviate.Client.ICredentials? credentials = null, string! hostname = "localhost", ushort restPort = 8080, ushort grpcPort = 50051, bool useSsl = false, System.Collections.Generic.Dictionary? headers = null, System.Net.Http.HttpMessageHandler? httpMessageHandler = null, System.TimeSpan? defaultTimeout = null, System.TimeSpan? initTimeout = null, System.TimeSpan? insertTimeout = null, System.TimeSpan? queryTimeout = null) -> System.Threading.Tasks.Task! +static Weaviate.Client.ExportClient.Config.get -> Weaviate.Client.Models.ExportClientConfig! +static Weaviate.Client.ExportClient.Config.set -> void static Weaviate.Client.DependencyInjection.WeaviateServiceCollectionExtensions.AddWeaviate(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, Microsoft.Extensions.Configuration.IConfiguration! configuration, bool eagerInitialization = true) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Weaviate.Client.DependencyInjection.WeaviateServiceCollectionExtensions.AddWeaviate(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action! configureOptions, bool eagerInitialization = true) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Weaviate.Client.DependencyInjection.WeaviateServiceCollectionExtensions.AddWeaviateClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, string! name, System.Action! configureOptions) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! @@ -1440,6 +1469,14 @@ static Weaviate.Client.Models.DataReference.operator !=(Weaviate.Client.Models.D static Weaviate.Client.Models.DataReference.operator ==(Weaviate.Client.Models.DataReference? left, Weaviate.Client.Models.DataReference? right) -> bool static Weaviate.Client.Models.DataResource.operator !=(Weaviate.Client.Models.DataResource? left, Weaviate.Client.Models.DataResource? right) -> bool static Weaviate.Client.Models.DataResource.operator ==(Weaviate.Client.Models.DataResource? left, Weaviate.Client.Models.DataResource? right) -> bool +static Weaviate.Client.Models.Export.operator !=(Weaviate.Client.Models.Export? left, Weaviate.Client.Models.Export? right) -> bool +static Weaviate.Client.Models.Export.operator ==(Weaviate.Client.Models.Export? left, Weaviate.Client.Models.Export? right) -> bool +static Weaviate.Client.Models.ExportClientConfig.Default.get -> Weaviate.Client.Models.ExportClientConfig! +static Weaviate.Client.Models.ExportClientConfig.operator !=(Weaviate.Client.Models.ExportClientConfig? left, Weaviate.Client.Models.ExportClientConfig? right) -> bool +static Weaviate.Client.Models.ExportClientConfig.operator ==(Weaviate.Client.Models.ExportClientConfig? left, Weaviate.Client.Models.ExportClientConfig? right) -> bool +static Weaviate.Client.Models.ExportCreateRequest.operator !=(Weaviate.Client.Models.ExportCreateRequest? left, Weaviate.Client.Models.ExportCreateRequest? right) -> bool +static Weaviate.Client.Models.ExportCreateRequest.operator ==(Weaviate.Client.Models.ExportCreateRequest? left, Weaviate.Client.Models.ExportCreateRequest? right) -> bool +static Weaviate.Client.Models.ExportStatusExtensions.ToExportStatus(this string? status) -> Weaviate.Client.Models.ExportStatus static Weaviate.Client.Models.FilesystemBackend.operator !=(Weaviate.Client.Models.FilesystemBackend? left, Weaviate.Client.Models.FilesystemBackend? right) -> bool static Weaviate.Client.Models.FilesystemBackend.operator ==(Weaviate.Client.Models.FilesystemBackend? left, Weaviate.Client.Models.FilesystemBackend? right) -> bool static Weaviate.Client.Models.Filter.AllOf(params Weaviate.Client.Models.Filter![]! filters) -> Weaviate.Client.Models.Filter! @@ -1714,6 +1751,8 @@ static Weaviate.Client.Models.ShardingConfig.Default.get -> Weaviate.Client.Mode static Weaviate.Client.Models.ShardingConfig.operator !=(Weaviate.Client.Models.ShardingConfig? left, Weaviate.Client.Models.ShardingConfig? right) -> bool static Weaviate.Client.Models.ShardingConfig.operator ==(Weaviate.Client.Models.ShardingConfig? left, Weaviate.Client.Models.ShardingConfig? right) -> bool static Weaviate.Client.Models.ShardingConfig.Zero.get -> Weaviate.Client.Models.ShardingConfig! +static Weaviate.Client.Models.ShardProgress.operator !=(Weaviate.Client.Models.ShardProgress? left, Weaviate.Client.Models.ShardProgress? right) -> bool +static Weaviate.Client.Models.ShardProgress.operator ==(Weaviate.Client.Models.ShardProgress? left, Weaviate.Client.Models.ShardProgress? right) -> bool static Weaviate.Client.Models.SimpleTargetVectors.operator !=(Weaviate.Client.Models.SimpleTargetVectors? left, Weaviate.Client.Models.SimpleTargetVectors? right) -> bool static Weaviate.Client.Models.SimpleTargetVectors.operator ==(Weaviate.Client.Models.SimpleTargetVectors? left, Weaviate.Client.Models.SimpleTargetVectors? right) -> bool static Weaviate.Client.Models.SinglePrompt.implicit operator Weaviate.Client.Models.SinglePrompt!(string! prompt) -> Weaviate.Client.Models.SinglePrompt! @@ -2201,6 +2240,19 @@ virtual Weaviate.Client.Models.DataResource.$() -> Weaviate.Client.Models virtual Weaviate.Client.Models.DataResource.EqualityContract.get -> System.Type! virtual Weaviate.Client.Models.DataResource.Equals(Weaviate.Client.Models.DataResource? other) -> bool virtual Weaviate.Client.Models.DataResource.PrintMembers(System.Text.StringBuilder! builder) -> bool +virtual Weaviate.Client.Models.Export.$() -> Weaviate.Client.Models.Export! +virtual Weaviate.Client.Models.Export.EqualityContract.get -> System.Type! +virtual Weaviate.Client.Models.Export.Equals(Weaviate.Client.Models.Export? other) -> bool +virtual Weaviate.Client.Models.Export.PrintMembers(System.Text.StringBuilder! builder) -> bool +virtual Weaviate.Client.Models.ExportClientConfig.$() -> Weaviate.Client.Models.ExportClientConfig! +virtual Weaviate.Client.Models.ExportClientConfig.EqualityContract.get -> System.Type! +virtual Weaviate.Client.Models.ExportClientConfig.Equals(Weaviate.Client.Models.ExportClientConfig? other) -> bool +virtual Weaviate.Client.Models.ExportClientConfig.PrintMembers(System.Text.StringBuilder! builder) -> bool +virtual Weaviate.Client.Models.ExportCreateRequest.$() -> Weaviate.Client.Models.ExportCreateRequest! +virtual Weaviate.Client.Models.ExportCreateRequest.EqualityContract.get -> System.Type! +virtual Weaviate.Client.Models.ExportCreateRequest.Equals(Weaviate.Client.Models.ExportCreateRequest? other) -> bool +virtual Weaviate.Client.Models.ExportCreateRequest.PrintMembers(System.Text.StringBuilder! builder) -> bool +virtual Weaviate.Client.Models.ExportOperationBase.Dispose(bool disposing) -> void virtual Weaviate.Client.Models.FilesystemBackend.Equals(Weaviate.Client.Models.FilesystemBackend? other) -> bool virtual Weaviate.Client.Models.Filter.$() -> Weaviate.Client.Models.Filter! virtual Weaviate.Client.Models.Filter.EqualityContract.get -> System.Type! @@ -2494,6 +2546,10 @@ virtual Weaviate.Client.Models.ShardingConfig.$() -> Weaviate.Client.Mode virtual Weaviate.Client.Models.ShardingConfig.EqualityContract.get -> System.Type! virtual Weaviate.Client.Models.ShardingConfig.Equals(Weaviate.Client.Models.ShardingConfig? other) -> bool virtual Weaviate.Client.Models.ShardingConfig.PrintMembers(System.Text.StringBuilder! builder) -> bool +virtual Weaviate.Client.Models.ShardProgress.$() -> Weaviate.Client.Models.ShardProgress! +virtual Weaviate.Client.Models.ShardProgress.EqualityContract.get -> System.Type! +virtual Weaviate.Client.Models.ShardProgress.Equals(Weaviate.Client.Models.ShardProgress? other) -> bool +virtual Weaviate.Client.Models.ShardProgress.PrintMembers(System.Text.StringBuilder! builder) -> bool virtual Weaviate.Client.Models.SinglePrompt.Equals(Weaviate.Client.Models.SinglePrompt? other) -> bool virtual Weaviate.Client.Models.Sort.$() -> Weaviate.Client.Models.Sort! virtual Weaviate.Client.Models.Sort.EqualityContract.get -> System.Type! @@ -2879,6 +2935,11 @@ Weaviate.Client.DefaultTokenServiceFactory Weaviate.Client.DefaultTokenServiceFactory.CreateAsync(Weaviate.Client.ClientConfiguration! configuration) -> System.Threading.Tasks.Task! Weaviate.Client.DefaultTokenServiceFactory.CreateSync(Weaviate.Client.ClientConfiguration! configuration) -> Weaviate.Client.ITokenService? Weaviate.Client.DefaultTokenServiceFactory.DefaultTokenServiceFactory() -> void +Weaviate.Client.ExportClient +Weaviate.Client.ExportClient.Cancel(Weaviate.Client.Models.BackupBackend! backend, string! id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Weaviate.Client.ExportClient.Create(Weaviate.Client.Models.ExportCreateRequest! request, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Weaviate.Client.ExportClient.CreateSync(Weaviate.Client.Models.ExportCreateRequest! request, System.TimeSpan? timeout = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Weaviate.Client.ExportClient.GetStatus(Weaviate.Client.Models.BackupBackend! backend, string! id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! Weaviate.Client.DependencyInjection.IWeaviateClientFactory Weaviate.Client.DependencyInjection.IWeaviateClientFactory.GetClient(string! name) -> Weaviate.Client.WeaviateClient! Weaviate.Client.DependencyInjection.IWeaviateClientFactory.GetClientAsync(string! name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! @@ -3641,6 +3702,73 @@ Weaviate.Client.Models.DeletionStrategy.NoAutomatedResolution = 0 -> Weaviate.Cl Weaviate.Client.Models.DeletionStrategy.TimeBasedResolution = 2 -> Weaviate.Client.Models.DeletionStrategy Weaviate.Client.Models.EmptyStringEnumConverter Weaviate.Client.Models.EmptyStringEnumConverter.EmptyStringEnumConverter() -> void +Weaviate.Client.Models.Export +Weaviate.Client.Models.Export.Backend.get -> Weaviate.Client.Models.BackupBackend! +Weaviate.Client.Models.Export.Backend.init -> void +Weaviate.Client.Models.Export.Collections.get -> string![]? +Weaviate.Client.Models.Export.Collections.init -> void +Weaviate.Client.Models.Export.CompletedAt.get -> System.DateTimeOffset? +Weaviate.Client.Models.Export.CompletedAt.init -> void +Weaviate.Client.Models.Export.Deconstruct(out string! Id, out Weaviate.Client.Models.BackupBackend! Backend, out string? Path, out string! StatusRaw, out string![]? Collections, out System.DateTimeOffset? StartedAt, out System.DateTimeOffset? CompletedAt, out string? Error) -> void +Weaviate.Client.Models.Export.Error.get -> string? +Weaviate.Client.Models.Export.Error.init -> void +Weaviate.Client.Models.Export.Export(Weaviate.Client.Models.Export! original) -> void +Weaviate.Client.Models.Export.Export(string! Id, Weaviate.Client.Models.BackupBackend! Backend, string? Path, string! StatusRaw, string![]? Collections, System.DateTimeOffset? StartedAt, System.DateTimeOffset? CompletedAt, string? Error) -> void +Weaviate.Client.Models.Export.Path.get -> string? +Weaviate.Client.Models.Export.Path.init -> void +Weaviate.Client.Models.Export.Id.get -> string! +Weaviate.Client.Models.Export.Id.init -> void +Weaviate.Client.Models.Export.ShardStatus.get -> System.Collections.Generic.Dictionary!>? +Weaviate.Client.Models.Export.ShardStatus.init -> void +Weaviate.Client.Models.Export.StartedAt.get -> System.DateTimeOffset? +Weaviate.Client.Models.Export.StartedAt.init -> void +Weaviate.Client.Models.Export.Status.get -> Weaviate.Client.Models.ExportStatus +Weaviate.Client.Models.Export.StatusRaw.get -> string! +Weaviate.Client.Models.Export.StatusRaw.init -> void +Weaviate.Client.Models.Export.TookInMs.get -> int? +Weaviate.Client.Models.Export.TookInMs.init -> void +Weaviate.Client.Models.ExportClientConfig +Weaviate.Client.Models.ExportClientConfig.ExportClientConfig() -> void +Weaviate.Client.Models.ExportClientConfig.ExportClientConfig(Weaviate.Client.Models.ExportClientConfig! original) -> void +Weaviate.Client.Models.ExportClientConfig.PollInterval.get -> System.TimeSpan +Weaviate.Client.Models.ExportClientConfig.PollInterval.init -> void +Weaviate.Client.Models.ExportClientConfig.Timeout.get -> System.TimeSpan +Weaviate.Client.Models.ExportClientConfig.Timeout.init -> void +Weaviate.Client.Models.ExportCreateRequest +Weaviate.Client.Models.ExportCreateRequest.Backend.get -> Weaviate.Client.Models.BackupBackend! +Weaviate.Client.Models.ExportCreateRequest.Backend.init -> void +Weaviate.Client.Models.ExportCreateRequest.Deconstruct(out string! Id, out Weaviate.Client.Models.BackupBackend! Backend, out Weaviate.Client.Models.ExportFileFormat FileFormat, out Weaviate.Client.Internal.AutoArray? IncludeCollections, out Weaviate.Client.Internal.AutoArray? ExcludeCollections) -> void +Weaviate.Client.Models.ExportCreateRequest.ExcludeCollections.get -> Weaviate.Client.Internal.AutoArray? +Weaviate.Client.Models.ExportCreateRequest.ExcludeCollections.init -> void +Weaviate.Client.Models.ExportCreateRequest.ExportCreateRequest(Weaviate.Client.Models.ExportCreateRequest! original) -> void +Weaviate.Client.Models.ExportCreateRequest.ExportCreateRequest(string! Id, Weaviate.Client.Models.BackupBackend! Backend, Weaviate.Client.Models.ExportFileFormat FileFormat = Weaviate.Client.Models.ExportFileFormat.Parquet, Weaviate.Client.Internal.AutoArray? IncludeCollections = null, Weaviate.Client.Internal.AutoArray? ExcludeCollections = null) -> void +Weaviate.Client.Models.ExportCreateRequest.FileFormat.get -> Weaviate.Client.Models.ExportFileFormat +Weaviate.Client.Models.ExportCreateRequest.FileFormat.init -> void +Weaviate.Client.Models.ExportCreateRequest.Id.get -> string! +Weaviate.Client.Models.ExportCreateRequest.Id.init -> void +Weaviate.Client.Models.ExportCreateRequest.IncludeCollections.get -> Weaviate.Client.Internal.AutoArray? +Weaviate.Client.Models.ExportCreateRequest.IncludeCollections.init -> void +Weaviate.Client.Models.ExportFileFormat +Weaviate.Client.Models.ExportFileFormat.Parquet = 0 -> Weaviate.Client.Models.ExportFileFormat +Weaviate.Client.Models.ExportOperation +Weaviate.Client.Models.ExportOperationBase +Weaviate.Client.Models.ExportOperationBase.Cancel(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Weaviate.Client.Models.ExportOperationBase.Current.get -> Weaviate.Client.Models.Export! +Weaviate.Client.Models.ExportOperationBase.Dispose() -> void +Weaviate.Client.Models.ExportOperationBase.DisposeAsync() -> System.Threading.Tasks.ValueTask +Weaviate.Client.Models.ExportOperationBase.ExportOperationBase(Weaviate.Client.Models.Export! initial, System.Func!>! statusFetcher, System.Func! operationCancel) -> void +Weaviate.Client.Models.ExportOperationBase.IsCanceled.get -> bool +Weaviate.Client.Models.ExportOperationBase.IsCompleted.get -> bool +Weaviate.Client.Models.ExportOperationBase.IsSuccessful.get -> bool +Weaviate.Client.Models.ExportOperationBase.WaitForCompletion(System.TimeSpan? timeout = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +Weaviate.Client.Models.ExportStatus +Weaviate.Client.Models.ExportStatus.Canceled = 5 -> Weaviate.Client.Models.ExportStatus +Weaviate.Client.Models.ExportStatus.Failed = 4 -> Weaviate.Client.Models.ExportStatus +Weaviate.Client.Models.ExportStatus.Started = 1 -> Weaviate.Client.Models.ExportStatus +Weaviate.Client.Models.ExportStatus.Success = 3 -> Weaviate.Client.Models.ExportStatus +Weaviate.Client.Models.ExportStatus.Transferring = 2 -> Weaviate.Client.Models.ExportStatus +Weaviate.Client.Models.ExportStatus.Unknown = 0 -> Weaviate.Client.Models.ExportStatus +Weaviate.Client.Models.ExportStatusExtensions Weaviate.Client.Models.FilesystemBackend Weaviate.Client.Models.FilesystemBackend.FilesystemBackend(string? path = null) -> void Weaviate.Client.Models.FilesystemBackend.FilesystemBackend(Weaviate.Client.Models.FilesystemBackend! original) -> void @@ -5154,6 +5282,18 @@ Weaviate.Client.Models.ShardingConfig.Strategy.get -> Weaviate.Client.Models.Sha Weaviate.Client.Models.ShardingConfig.Strategy.set -> void Weaviate.Client.Models.ShardingConfig.VirtualPerPhysical.get -> int Weaviate.Client.Models.ShardingConfig.VirtualPerPhysical.set -> void +Weaviate.Client.Models.ShardProgress +Weaviate.Client.Models.ShardProgress.Deconstruct(out string! StatusRaw, out int ObjectsExported, out string? Error, out string? SkipReason) -> void +Weaviate.Client.Models.ShardProgress.Error.get -> string? +Weaviate.Client.Models.ShardProgress.Error.init -> void +Weaviate.Client.Models.ShardProgress.ObjectsExported.get -> int +Weaviate.Client.Models.ShardProgress.ObjectsExported.init -> void +Weaviate.Client.Models.ShardProgress.ShardProgress(Weaviate.Client.Models.ShardProgress! original) -> void +Weaviate.Client.Models.ShardProgress.ShardProgress(string! StatusRaw, int ObjectsExported, string? Error, string? SkipReason) -> void +Weaviate.Client.Models.ShardProgress.SkipReason.get -> string? +Weaviate.Client.Models.ShardProgress.SkipReason.init -> void +Weaviate.Client.Models.ShardProgress.StatusRaw.get -> string! +Weaviate.Client.Models.ShardProgress.StatusRaw.init -> void Weaviate.Client.Models.ShardStatus Weaviate.Client.Models.ShardStatus.Indexing = 2 -> Weaviate.Client.Models.ShardStatus Weaviate.Client.Models.ShardStatus.ReadOnly = 1 -> Weaviate.Client.Models.ShardStatus @@ -6233,15 +6373,16 @@ Weaviate.Client.ResourceType Weaviate.Client.ResourceType.Alias = 0 -> Weaviate.Client.ResourceType Weaviate.Client.ResourceType.Backup = Weaviate.Client.ResourceType.Object | Weaviate.Client.ResourceType.User -> Weaviate.Client.ResourceType Weaviate.Client.ResourceType.Collection = 1 -> Weaviate.Client.ResourceType -Weaviate.Client.ResourceType.Group = Weaviate.Client.ResourceType.Collection | Weaviate.Client.ResourceType.Backup -> Weaviate.Client.ResourceType +Weaviate.Client.ResourceType.Export = Weaviate.Client.ResourceType.Collection | Weaviate.Client.ResourceType.Backup -> Weaviate.Client.ResourceType +Weaviate.Client.ResourceType.Group = 8 -> Weaviate.Client.ResourceType Weaviate.Client.ResourceType.Object = 2 -> Weaviate.Client.ResourceType Weaviate.Client.ResourceType.Property = Weaviate.Client.ResourceType.Collection | Weaviate.Client.ResourceType.Object -> Weaviate.Client.ResourceType -Weaviate.Client.ResourceType.Reference = 8 -> Weaviate.Client.ResourceType -Weaviate.Client.ResourceType.Replication = Weaviate.Client.ResourceType.Collection | Weaviate.Client.ResourceType.Tenant -> Weaviate.Client.ResourceType +Weaviate.Client.ResourceType.Reference = Weaviate.Client.ResourceType.Collection | Weaviate.Client.ResourceType.Group -> Weaviate.Client.ResourceType +Weaviate.Client.ResourceType.Replication = Weaviate.Client.ResourceType.User | Weaviate.Client.ResourceType.Group -> Weaviate.Client.ResourceType Weaviate.Client.ResourceType.Role = Weaviate.Client.ResourceType.Collection | Weaviate.Client.ResourceType.User -> Weaviate.Client.ResourceType -Weaviate.Client.ResourceType.Shard = Weaviate.Client.ResourceType.Collection | Weaviate.Client.ResourceType.Reference -> Weaviate.Client.ResourceType -Weaviate.Client.ResourceType.Tenant = Weaviate.Client.ResourceType.Object | Weaviate.Client.ResourceType.Reference -> Weaviate.Client.ResourceType -Weaviate.Client.ResourceType.Unknown = Weaviate.Client.ResourceType.User | Weaviate.Client.ResourceType.Reference -> Weaviate.Client.ResourceType +Weaviate.Client.ResourceType.Shard = Weaviate.Client.ResourceType.Object | Weaviate.Client.ResourceType.Group -> Weaviate.Client.ResourceType +Weaviate.Client.ResourceType.Tenant = Weaviate.Client.ResourceType.Collection | Weaviate.Client.ResourceType.Shard -> Weaviate.Client.ResourceType +Weaviate.Client.ResourceType.Unknown = Weaviate.Client.ResourceType.Collection | Weaviate.Client.ResourceType.Replication -> Weaviate.Client.ResourceType Weaviate.Client.ResourceType.User = 4 -> Weaviate.Client.ResourceType Weaviate.Client.RetryOn Weaviate.Client.RetryOn.NetworkError = 8 -> Weaviate.Client.RetryOn @@ -6542,6 +6683,7 @@ Weaviate.Client.WeaviateClient.Cluster.get -> Weaviate.Client.ClusterClient! Weaviate.Client.WeaviateClient.Collections.get -> Weaviate.Client.CollectionsClient! Weaviate.Client.WeaviateClient.Configuration.get -> Weaviate.Client.ClientConfiguration! Weaviate.Client.WeaviateClient.Dispose() -> void +Weaviate.Client.WeaviateClient.Export.get -> Weaviate.Client.ExportClient! Weaviate.Client.WeaviateClient.GetMeta(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! Weaviate.Client.WeaviateClient.Groups.get -> Weaviate.Client.GroupsClient! Weaviate.Client.WeaviateClient.InitializeAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! @@ -6794,7 +6936,6 @@ Weaviate.Client.Batch.BatchResult.ErrorMessage.get -> string? Weaviate.Client.Batch.BatchResult.ServerResponse.get -> object? Weaviate.Client.Batch.BatchResult.Success.get -> bool Weaviate.Client.Batch.BatchState -Weaviate.Client.Batch.BatchState.Aborted = 3 -> Weaviate.Client.Batch.BatchState Weaviate.Client.Batch.BatchState.Closed = 2 -> Weaviate.Client.Batch.BatchState Weaviate.Client.Batch.BatchState.InFlight = 1 -> Weaviate.Client.Batch.BatchState Weaviate.Client.Batch.BatchState.Open = 0 -> Weaviate.Client.Batch.BatchState diff --git a/src/Weaviate.Client/Rest/Dto/Models.g.cs b/src/Weaviate.Client/Rest/Dto/Models.g.cs index a10bb20f..78ca2147 100644 --- a/src/Weaviate.Client/Rest/Dto/Models.g.cs +++ b/src/Weaviate.Client/Rest/Dto/Models.g.cs @@ -558,14 +558,6 @@ internal partial record ExportCreateRequest public System.Collections.Generic.IList? Exclude { get; set; } = default!; - /// - /// Backend-specific configuration - /// - - [System.Text.Json.Serialization.JsonPropertyName("config")] - - public Config? Config { get; set; } = default!; - } /// @@ -894,6 +886,14 @@ internal partial record InvertedIndexConfig public System.Collections.Generic.IList? TokenizerUserDict { get; set; } = default!; + /// + /// User-defined named stopword lists. Each key is a preset name that can be referenced by a property's textAnalyzer.stopwordPreset field. The value is an array of stopword strings. + /// + + [System.Text.Json.Serialization.JsonPropertyName("stopwordPresets")] + + public System.Collections.Generic.IDictionary>? StopwordPresets { get; set; } = default!; + } /// @@ -1047,12 +1047,12 @@ internal partial record TokenizeRequest public TextAnalyzerConfig? AnalyzerConfig { get; set; } = default!; /// - /// Optional stopword configuration. When provided, stopwords are removed from query tokens but preserved in indexed tokens. + /// Optional named stopword configurations. Each key is a preset name that can be referenced by analyzerConfig.stopwordPreset. Each value is a StopwordConfig (with optional preset, additions, and removals). /// - [System.Text.Json.Serialization.JsonPropertyName("stopwordConfig")] + [System.Text.Json.Serialization.JsonPropertyName("stopwordPresets")] - public StopwordConfig? StopwordConfig { get; set; } = default!; + public System.Collections.Generic.IDictionary? StopwordPresets { get; set; } = default!; } @@ -1953,6 +1953,14 @@ internal partial record TextAnalyzerConfig public System.Collections.Generic.IList? AsciiFoldIgnore { get; set; } = default!; + /// + /// Stopword preset name. Overrides the collection-level invertedIndexConfig.stopwords for this property. Only applies to properties using 'word' tokenization. Can be a built-in preset ('en', 'none') or a user-defined preset from invertedIndexConfig.stopwordPresets. + /// + + [System.Text.Json.Serialization.JsonPropertyName("stopwordPreset")] + + public string? StopwordPreset { get; set; } = default!; + } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.6.1.0 (NJsonSchema v11.5.1.0 (Newtonsoft.Json v13.0.0.0))")] @@ -4721,11 +4729,11 @@ internal enum PermissionAction [System.Text.Json.Serialization.JsonStringEnumMemberName(@"read_groups")] Read_groups = 33, - [System.Text.Json.Serialization.JsonStringEnumMemberName(@"read_mcp")] - Read_mcp = 34, - [System.Text.Json.Serialization.JsonStringEnumMemberName(@"create_mcp")] - Create_mcp = 35, + Create_mcp = 34, + + [System.Text.Json.Serialization.JsonStringEnumMemberName(@"read_mcp")] + Read_mcp = 35, [System.Text.Json.Serialization.JsonStringEnumMemberName(@"update_mcp")] Update_mcp = 36, @@ -4791,19 +4799,6 @@ internal enum ExportCreateRequestFile_format } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.6.1.0 (NJsonSchema v11.5.1.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial record Config - { - /// - /// Path prefix within the bucket or filesystem - /// - - [System.Text.Json.Serialization.JsonPropertyName("path")] - - public string? Path { get; set; } = default!; - - } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.6.1.0 (NJsonSchema v11.5.1.0 (Newtonsoft.Json v13.0.0.0))")] internal enum ExportCreateResponseStatus { diff --git a/src/Weaviate.Client/Rest/Endpoints.cs b/src/Weaviate.Client/Rest/Endpoints.cs index d52c1f12..c989487c 100644 --- a/src/Weaviate.Client/Rest/Endpoints.cs +++ b/src/Weaviate.Client/Rest/Endpoints.cs @@ -313,6 +313,11 @@ internal static string BackupRestoreStatus( return ep; } + // Export endpoints + internal static string Exports(string backend) => $"export/{backend}"; + + internal static string ExportStatus(string backend, string id) => $"export/{backend}/{id}"; + // Users endpoints /// /// Userses the own info diff --git a/src/Weaviate.Client/Rest/Export.cs b/src/Weaviate.Client/Rest/Export.cs new file mode 100644 index 00000000..3f539670 --- /dev/null +++ b/src/Weaviate.Client/Rest/Export.cs @@ -0,0 +1,55 @@ +using System.Net; +using System.Net.Http.Json; +using Weaviate.Client.Models; + +namespace Weaviate.Client.Rest; + +internal partial class WeaviateRestClient +{ + internal async Task ExportCreate( + BackupStorageProvider backend, + Dto.ExportCreateRequest request, + CancellationToken cancellationToken = default + ) + { + var response = await _httpClient.PostAsJsonAsync( + WeaviateEndpoints.Exports(backend.ToEnumMemberString()!), + request, + options: RestJsonSerializerOptions, + cancellationToken: cancellationToken + ); + await response.ManageStatusCode([HttpStatusCode.OK], "create export", ResourceType.Export); + return await response.DecodeAsync(cancellationToken); + } + + internal async Task ExportGetStatus( + BackupStorageProvider backend, + string id, + CancellationToken cancellationToken = default + ) + { + var response = await _httpClient.GetAsync( + WeaviateEndpoints.ExportStatus(backend.ToEnumMemberString()!, id), + cancellationToken + ); + await response.ManageStatusCode([HttpStatusCode.OK], "export status", ResourceType.Export); + return await response.DecodeAsync(cancellationToken); + } + + internal async Task ExportCancel( + BackupStorageProvider backend, + string id, + CancellationToken cancellationToken = default + ) + { + var response = await _httpClient.DeleteAsync( + WeaviateEndpoints.ExportStatus(backend.ToEnumMemberString()!, id), + cancellationToken + ); + await response.ManageStatusCode( + [HttpStatusCode.OK, HttpStatusCode.NoContent], + "export cancel", + ResourceType.Export + ); + } +} diff --git a/src/Weaviate.Client/Rest/Schema/openapi.json b/src/Weaviate.Client/Rest/Schema/openapi.json index 0631d15d..53f585ba 100644 --- a/src/Weaviate.Client/Rest/Schema/openapi.json +++ b/src/Weaviate.Client/Rest/Schema/openapi.json @@ -345,8 +345,8 @@ "delete_aliases", "assign_and_revoke_groups", "read_groups", - "read_mcp", "create_mcp", + "read_mcp", "update_mcp" ] } @@ -607,16 +607,6 @@ "type": "string" }, "description": "List of collection names to exclude from the export. Cannot be used with 'include'." - }, - "config": { - "type": "object", - "description": "Backend-specific configuration", - "properties": { - "path": { - "type": "string", - "description": "Path prefix within the bucket or filesystem" - } - } } } }, @@ -857,6 +847,17 @@ "items": { "$ref": "#/definitions/TokenizerUserDictConfig" } + }, + "stopwordPresets": { + "description": "User-defined named stopword lists. Each key is a preset name that can be referenced by a property's textAnalyzer.stopwordPreset field. The value is an array of stopword strings.", + "type": "object", + "x-omitempty": true, + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } } }, "type": "object" @@ -989,9 +990,13 @@ "description": "Optional text analyzer configuration (e.g. ASCII folding).", "$ref": "#/definitions/TextAnalyzerConfig" }, - "stopwordConfig": { - "description": "Optional stopword configuration. When provided, stopwords are removed from query tokens but preserved in indexed tokens.", - "$ref": "#/definitions/StopwordConfig" + "stopwordPresets": { + "description": "Optional named stopword configurations. Each key is a preset name that can be referenced by analyzerConfig.stopwordPreset. Each value is a StopwordConfig (with optional preset, additions, and removals).", + "type": "object", + "x-omitempty": true, + "additionalProperties": { + "$ref": "#/definitions/StopwordConfig" + } } } }, @@ -1654,6 +1659,11 @@ "items": { "type": "string" } + }, + "stopwordPreset": { + "description": "Stopword preset name. Overrides the collection-level invertedIndexConfig.stopwords for this property. Only applies to properties using 'word' tokenization. Can be a built-in preset ('en', 'none') or a user-defined preset from invertedIndexConfig.stopwordPresets.", + "type": "string", + "x-omitempty": true } }, "x-omitempty": true, @@ -3470,7 +3480,7 @@ }, "description": "# Introduction
Weaviate is an open source, AI-native vector database that helps developers create intuitive and reliable AI-powered applications.
### Base Path
The base path for the Weaviate server is structured as `[YOUR-WEAVIATE-HOST]:[PORT]/v1`. As an example, if you wish to access the `schema` endpoint on a local instance, you would navigate to `http://localhost:8080/v1/schema`. Ensure you replace `[YOUR-WEAVIATE-HOST]` and `[PORT]` with your actual server host and port number respectively.
### Questions?
If you have any comments or questions, please feel free to reach out to us at the community forum [https://forum.weaviate.io/](https://forum.weaviate.io/).
### Issues?
If you find a bug or want to file a feature request, please open an issue on our GitHub repository for [Weaviate](https://github.com/weaviate/weaviate).
### Need more documentation?
For a quickstart, code examples, concepts and more, please visit our [documentation page](https://docs.weaviate.io/weaviate).", "title": "Weaviate REST API", - "version": "1.37.0-rc.0" + "version": "1.37.1" }, "parameters": { "CommonAfterParameterQuery": { @@ -8145,61 +8155,6 @@ } } }, - "/schema/{className}/vectors/{vectorIndexName}/index": { - "delete": { - "summary": "Delete a collection's vector index.", - "description": "Deletes a specific vector index within a collection (`className`). The vector index to delete is identified by `vectorIndexName`.", - "operationId": "schema.objects.vectors.delete", - "x-serviceIds": [ - "weaviate.local.manipulate.meta" - ], - "tags": [ - "schema" - ], - "parameters": [ - { - "name": "className", - "description": "The name of the collection (class) containing the property.", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "vectorIndexName", - "description": "The name of the vector index.", - "in": "path", - "required": true, - "type": "string" - } - ], - "responses": { - "200": { - "description": "Vector index deleted successfully." - }, - "401": { - "description": "Unauthorized or invalid credentials." - }, - "403": { - "description": "Forbidden", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - }, - "422": { - "description": "Invalid vector index or collection provided.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - }, - "500": { - "description": "An error occurred while deleting the vector index. Check the ErrorResponse for details.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - } - }, "/schema/{className}/properties/{propertyName}/tokenize": { "post": { "summary": "Tokenize text using a property's configuration", @@ -9648,13 +9603,6 @@ "required": true, "type": "string", "description": "The unique identifier of the export." - }, - { - "name": "path", - "in": "query", - "required": false, - "type": "string", - "description": "Optional path prefix within the bucket. If not specified, uses the backend's default path." } ], "responses": { @@ -9717,13 +9665,6 @@ "required": true, "type": "string", "description": "The unique identifier of the export to cancel." - }, - { - "name": "path", - "in": "query", - "required": false, - "type": "string", - "description": "Optional path prefix within the bucket." } ], "responses": {