Harden Surreal migration with retry/coverage fixes and XML docs cleanup
All checks were successful
NuGet Package Publish / nuget (push) Successful in 1m17s
All checks were successful
NuGet Package Publish / nuget (push) Successful in 1m17s
This commit is contained in:
@@ -55,14 +55,16 @@ public class RetryPolicy : IRetryPolicy
|
||||
|
||||
return await operation();
|
||||
}
|
||||
catch (Exception ex) when (attempt < config.RetryAttempts && IsTransient(ex))
|
||||
{
|
||||
lastException = ex;
|
||||
int delay = config.RetryDelayMs * attempt; // Exponential backoff
|
||||
|
||||
_logger.LogWarning(ex,
|
||||
"Operation {Operation} failed (attempt {Attempt}/{Max}). Retrying in {Delay}ms...",
|
||||
operationName, attempt, config.RetryAttempts, delay);
|
||||
catch (Exception ex) when (IsTransient(ex))
|
||||
{
|
||||
lastException = ex;
|
||||
if (attempt >= config.RetryAttempts) break;
|
||||
|
||||
int delay = config.RetryDelayMs * attempt; // Exponential backoff
|
||||
|
||||
_logger.LogWarning(ex,
|
||||
"Operation {Operation} failed (attempt {Attempt}/{Max}). Retrying in {Delay}ms...",
|
||||
operationName, attempt, config.RetryAttempts, delay);
|
||||
|
||||
await Task.Delay(delay, cancellationToken);
|
||||
}
|
||||
@@ -111,4 +113,4 @@ public class RetryPolicy : IRetryPolicy
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,15 @@ public interface ICBDDCSurrealEmbeddedClient : IAsyncDisposable, IDisposable
|
||||
/// <summary>
|
||||
/// Connects and selects namespace/database exactly once.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
Task InitializeAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Executes a raw SurrealQL statement.
|
||||
/// </summary>
|
||||
/// <param name="query">The SurrealQL query to execute.</param>
|
||||
/// <param name="parameters">Optional named parameters for the query.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
Task<SurrealDbResponse> RawQueryAsync(string query,
|
||||
IReadOnlyDictionary<string, object?>? parameters = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
@@ -28,5 +32,6 @@ public interface ICBDDCSurrealEmbeddedClient : IAsyncDisposable, IDisposable
|
||||
/// <summary>
|
||||
/// Checks whether the embedded client responds to health probes.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
Task<bool> HealthAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@ public interface ICBDDCSurrealReadinessProbe
|
||||
/// <summary>
|
||||
/// Returns true when client initialization, schema initialization, and health checks pass.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
Task<bool> IsReadyAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@ public interface ICBDDCSurrealSchemaInitializer
|
||||
/// <summary>
|
||||
/// Creates required tables/indexes/checkpoint schema for CBDDC stores.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
Task EnsureInitializedAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -13,15 +13,18 @@ public interface ISurrealCdcWorkerLifecycle
|
||||
/// <summary>
|
||||
/// Starts the CDC worker.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The token used to cancel the asynchronous operation.</param>
|
||||
Task StartCdcWorkerAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Executes one CDC polling pass across all watched collections.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The token used to cancel the asynchronous operation.</param>
|
||||
Task PollCdcOnceAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Stops the CDC worker.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The token used to cancel the asynchronous operation.</param>
|
||||
Task StopCdcWorkerAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -150,30 +150,56 @@ public sealed class SurrealCdcCheckpointPersistence : ISurrealCdcCheckpointPersi
|
||||
|
||||
internal sealed class SurrealCdcCheckpointRecord : Record
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the CDC consumer identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("consumerId")]
|
||||
public string ConsumerId { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the physical time component of the checkpoint timestamp.
|
||||
/// </summary>
|
||||
[JsonPropertyName("timestampPhysicalTime")]
|
||||
public long TimestampPhysicalTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the logical counter component of the checkpoint timestamp.
|
||||
/// </summary>
|
||||
[JsonPropertyName("timestampLogicalCounter")]
|
||||
public int TimestampLogicalCounter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the node identifier component of the checkpoint timestamp.
|
||||
/// </summary>
|
||||
[JsonPropertyName("timestampNodeId")]
|
||||
public string TimestampNodeId { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the hash associated with the checkpoint.
|
||||
/// </summary>
|
||||
[JsonPropertyName("lastHash")]
|
||||
public string LastHash { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the last update time in Unix milliseconds.
|
||||
/// </summary>
|
||||
[JsonPropertyName("updatedUtcMs")]
|
||||
public long UpdatedUtcMs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the optional encoded versionstamp cursor.
|
||||
/// </summary>
|
||||
[JsonPropertyName("versionstampCursor")]
|
||||
public long? VersionstampCursor { get; set; }
|
||||
}
|
||||
|
||||
internal static class SurrealCdcCheckpointRecordMappers
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a checkpoint record into the domain checkpoint model.
|
||||
/// </summary>
|
||||
/// <param name="record">The Surreal checkpoint record.</param>
|
||||
/// <returns>The mapped domain checkpoint instance.</returns>
|
||||
public static SurrealCdcCheckpoint ToDomain(this SurrealCdcCheckpointRecord record)
|
||||
{
|
||||
return new SurrealCdcCheckpoint
|
||||
|
||||
@@ -13,6 +13,12 @@ public class SurrealDocumentMetadataStore : DocumentMetadataStore
|
||||
private readonly ICBDDCSurrealSchemaInitializer _schemaInitializer;
|
||||
private readonly ISurrealDbClient _surrealClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SurrealDocumentMetadataStore" /> class.
|
||||
/// </summary>
|
||||
/// <param name="surrealEmbeddedClient">The embedded Surreal client provider.</param>
|
||||
/// <param name="schemaInitializer">The schema initializer.</param>
|
||||
/// <param name="logger">Optional logger.</param>
|
||||
public SurrealDocumentMetadataStore(
|
||||
ICBDDCSurrealEmbeddedClient surrealEmbeddedClient,
|
||||
ICBDDCSurrealSchemaInitializer schemaInitializer,
|
||||
@@ -24,6 +30,7 @@ public class SurrealDocumentMetadataStore : DocumentMetadataStore
|
||||
_logger = logger ?? NullLogger<SurrealDocumentMetadataStore>.Instance;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<DocumentMetadata?> GetMetadataAsync(string collection, string key,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -31,6 +38,7 @@ public class SurrealDocumentMetadataStore : DocumentMetadataStore
|
||||
return existing?.ToDomain();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<DocumentMetadata>> GetMetadataByCollectionAsync(string collection,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -41,6 +49,7 @@ public class SurrealDocumentMetadataStore : DocumentMetadataStore
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task UpsertMetadataAsync(DocumentMetadata metadata,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -55,6 +64,7 @@ public class SurrealDocumentMetadataStore : DocumentMetadataStore
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task UpsertMetadataBatchAsync(IEnumerable<DocumentMetadata> metadatas,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -62,6 +72,7 @@ public class SurrealDocumentMetadataStore : DocumentMetadataStore
|
||||
await UpsertMetadataAsync(metadata, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task MarkDeletedAsync(string collection, string key, HlcTimestamp timestamp,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -69,6 +80,7 @@ public class SurrealDocumentMetadataStore : DocumentMetadataStore
|
||||
await UpsertMetadataAsync(metadata, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<DocumentMetadata>> GetMetadataAfterAsync(HlcTimestamp since,
|
||||
IEnumerable<string>? collections = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -86,24 +98,28 @@ public class SurrealDocumentMetadataStore : DocumentMetadataStore
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task DropAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await EnsureReadyAsync(cancellationToken);
|
||||
await _surrealClient.Delete(CBDDCSurrealSchemaNames.DocumentMetadataTable, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<DocumentMetadata>> ExportAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var all = await SelectAllAsync(cancellationToken);
|
||||
return all.Select(m => m.ToDomain()).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task ImportAsync(IEnumerable<DocumentMetadata> items,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
foreach (var item in items) await UpsertMetadataAsync(item, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task MergeAsync(IEnumerable<DocumentMetadata> items,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
@@ -61,6 +61,15 @@ public abstract class SurrealDocumentStore<TContext> : IDocumentStore, ISurrealC
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SurrealDocumentStore{TContext}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="context">The application context used by the concrete store.</param>
|
||||
/// <param name="surrealEmbeddedClient">The embedded Surreal client provider.</param>
|
||||
/// <param name="schemaInitializer">The Surreal schema initializer.</param>
|
||||
/// <param name="configProvider">The peer node configuration provider.</param>
|
||||
/// <param name="vectorClockService">The vector clock service used for local oplog state.</param>
|
||||
/// <param name="conflictResolver">Optional conflict resolver; defaults to last-write-wins.</param>
|
||||
/// <param name="checkpointPersistence">Optional CDC checkpoint persistence component.</param>
|
||||
/// <param name="cdcPollingOptions">Optional CDC polling options.</param>
|
||||
/// <param name="logger">Optional logger instance.</param>
|
||||
protected SurrealDocumentStore(
|
||||
TContext context,
|
||||
ICBDDCSurrealEmbeddedClient surrealEmbeddedClient,
|
||||
@@ -128,21 +137,28 @@ public abstract class SurrealDocumentStore<TContext> : IDocumentStore, ISurrealC
|
||||
{
|
||||
private readonly ILogger _inner;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ForwardingLogger" /> class.
|
||||
/// </summary>
|
||||
/// <param name="inner">The logger instance to forward calls to.</param>
|
||||
public ForwardingLogger(ILogger inner)
|
||||
{
|
||||
_inner = inner;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IDisposable? BeginScope<TState>(TState state) where TState : notnull
|
||||
{
|
||||
return _inner.BeginScope(state);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return _inner.IsEnabled(logLevel);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Log<TState>(
|
||||
LogLevel logLevel,
|
||||
EventId eventId,
|
||||
@@ -191,6 +207,7 @@ public abstract class SurrealDocumentStore<TContext> : IDocumentStore, ISurrealC
|
||||
/// <param name="collectionName">Logical collection name used by oplog and metadata records.</param>
|
||||
/// <param name="collection">Watchable change source.</param>
|
||||
/// <param name="keySelector">Function used to resolve the entity key.</param>
|
||||
/// <param name="subscribeForInMemoryEvents">Whether to subscribe to in-memory collection events.</param>
|
||||
protected void WatchCollection<TEntity>(
|
||||
string collectionName,
|
||||
ISurrealWatchableCollection<TEntity> collection,
|
||||
@@ -220,6 +237,12 @@ public abstract class SurrealDocumentStore<TContext> : IDocumentStore, ISurrealC
|
||||
private readonly Func<TEntity, string> _keySelector;
|
||||
private readonly SurrealDocumentStore<TContext> _store;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CdcObserver{TEntity}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="collectionName">The logical collection name.</param>
|
||||
/// <param name="keySelector">The key selector for observed entities.</param>
|
||||
/// <param name="store">The owning document store.</param>
|
||||
public CdcObserver(
|
||||
string collectionName,
|
||||
Func<TEntity, string> keySelector,
|
||||
@@ -230,6 +253,7 @@ public abstract class SurrealDocumentStore<TContext> : IDocumentStore, ISurrealC
|
||||
_store = store;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnNext(SurrealCollectionChange<TEntity> changeEvent)
|
||||
{
|
||||
if (_store.IsCdcPollingWorkerActiveForCollection(_collectionName)) return;
|
||||
@@ -267,10 +291,12 @@ public abstract class SurrealDocumentStore<TContext> : IDocumentStore, ISurrealC
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnError(Exception error)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnCompleted()
|
||||
{
|
||||
}
|
||||
@@ -760,22 +786,58 @@ public abstract class SurrealDocumentStore<TContext> : IDocumentStore, ISurrealC
|
||||
|
||||
#region Abstract Methods - Implemented by subclass
|
||||
|
||||
/// <summary>
|
||||
/// Applies JSON content to a single entity in the backing store.
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection name.</param>
|
||||
/// <param name="key">The document key.</param>
|
||||
/// <param name="content">The JSON payload to persist.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
protected abstract Task ApplyContentToEntityAsync(
|
||||
string collection, string key, JsonElement content, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Applies JSON content to multiple entities in the backing store.
|
||||
/// </summary>
|
||||
/// <param name="documents">The documents to persist.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
protected abstract Task ApplyContentToEntitiesBatchAsync(
|
||||
IEnumerable<(string Collection, string Key, JsonElement Content)> documents,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single entity as JSON content.
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection name.</param>
|
||||
/// <param name="key">The document key.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The JSON content when found; otherwise <see langword="null" />.</returns>
|
||||
protected abstract Task<JsonElement?> GetEntityAsJsonAsync(
|
||||
string collection, string key, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Removes a single entity from the backing store.
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection name.</param>
|
||||
/// <param name="key">The document key.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
protected abstract Task RemoveEntityAsync(
|
||||
string collection, string key, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Removes multiple entities from the backing store.
|
||||
/// </summary>
|
||||
/// <param name="documents">The documents to remove.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
protected abstract Task RemoveEntitiesBatchAsync(
|
||||
IEnumerable<(string Collection, string Key)> documents, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all entities from a collection as JSON content.
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection name.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>A sequence of key/content pairs.</returns>
|
||||
protected abstract Task<IEnumerable<(string Key, JsonElement Content)>> GetAllEntitiesAsJsonAsync(
|
||||
string collection, CancellationToken cancellationToken);
|
||||
|
||||
@@ -1055,6 +1117,12 @@ public abstract class SurrealDocumentStore<TContext> : IDocumentStore, ISurrealC
|
||||
/// <summary>
|
||||
/// Handles a local collection change and records oplog/metadata when not suppressed.
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection name.</param>
|
||||
/// <param name="key">The document key.</param>
|
||||
/// <param name="operationType">The detected operation type.</param>
|
||||
/// <param name="content">Optional JSON content for non-delete operations.</param>
|
||||
/// <param name="pendingCursorCheckpoint">Optional pending cursor checkpoint to persist.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
protected async Task OnLocalChangeDetectedAsync(
|
||||
string collection,
|
||||
string key,
|
||||
@@ -1315,11 +1383,16 @@ public abstract class SurrealDocumentStore<TContext> : IDocumentStore, ISurrealC
|
||||
private readonly SemaphoreSlim _guard;
|
||||
private int _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RemoteSyncScope" /> class.
|
||||
/// </summary>
|
||||
/// <param name="guard">The guard semaphore to release on dispose.</param>
|
||||
public RemoteSyncScope(SemaphoreSlim guard)
|
||||
{
|
||||
_guard = guard;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _disposed, 1) == 1) return;
|
||||
|
||||
@@ -127,6 +127,11 @@ public sealed class SurrealCollectionChangeFeed<TEntity> : ISurrealWatchableColl
|
||||
private readonly IObserver<SurrealCollectionChange<TEntity>> _observer;
|
||||
private int _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Subscription" /> class.
|
||||
/// </summary>
|
||||
/// <param name="owner">The owning change feed.</param>
|
||||
/// <param name="observer">The observer to unsubscribe on disposal.</param>
|
||||
public Subscription(
|
||||
SurrealCollectionChangeFeed<TEntity> owner,
|
||||
IObserver<SurrealCollectionChange<TEntity>> observer)
|
||||
@@ -135,6 +140,7 @@ public sealed class SurrealCollectionChangeFeed<TEntity> : ISurrealWatchableColl
|
||||
_observer = observer;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _disposed, 1) == 1) return;
|
||||
|
||||
@@ -14,6 +14,16 @@ public class SurrealOplogStore : OplogStore
|
||||
private readonly ICBDDCSurrealSchemaInitializer? _schemaInitializer;
|
||||
private readonly ISurrealDbClient? _surrealClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SurrealOplogStore" /> class.
|
||||
/// </summary>
|
||||
/// <param name="surrealEmbeddedClient">The Surreal embedded client provider.</param>
|
||||
/// <param name="schemaInitializer">The schema initializer used to prepare storage.</param>
|
||||
/// <param name="documentStore">The document store used for entity operations.</param>
|
||||
/// <param name="conflictResolver">The conflict resolver for replicated mutations.</param>
|
||||
/// <param name="vectorClockService">The vector clock service for causal ordering.</param>
|
||||
/// <param name="snapshotMetadataStore">The optional snapshot metadata store.</param>
|
||||
/// <param name="logger">The optional logger instance.</param>
|
||||
public SurrealOplogStore(
|
||||
ICBDDCSurrealEmbeddedClient surrealEmbeddedClient,
|
||||
ICBDDCSurrealSchemaInitializer schemaInitializer,
|
||||
@@ -36,6 +46,7 @@ public class SurrealOplogStore : OplogStore
|
||||
InitializeVectorClock();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<OplogEntry>> GetChainRangeAsync(string startHash, string endHash,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -61,12 +72,14 @@ public class SurrealOplogStore : OplogStore
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<OplogEntry?> GetEntryByHashAsync(string hash, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var existing = await FindByHashAsync(hash, cancellationToken);
|
||||
return existing?.ToDomain();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<OplogEntry>> GetOplogAfterAsync(HlcTimestamp timestamp,
|
||||
IEnumerable<string>? collections = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -85,6 +98,7 @@ public class SurrealOplogStore : OplogStore
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<OplogEntry>> GetOplogForNodeAfterAsync(string nodeId, HlcTimestamp since,
|
||||
IEnumerable<string>? collections = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -104,6 +118,7 @@ public class SurrealOplogStore : OplogStore
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task PruneOplogAsync(HlcTimestamp cutoff, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var all = await SelectAllAsync(cancellationToken);
|
||||
@@ -121,6 +136,7 @@ public class SurrealOplogStore : OplogStore
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task DropAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await EnsureReadyAsync(cancellationToken);
|
||||
@@ -128,12 +144,14 @@ public class SurrealOplogStore : OplogStore
|
||||
_vectorClock.Invalidate();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<OplogEntry>> ExportAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var all = await SelectAllAsync(cancellationToken);
|
||||
return all.Select(o => o.ToDomain()).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task ImportAsync(IEnumerable<OplogEntry> items, CancellationToken cancellationToken = default)
|
||||
{
|
||||
foreach (var item in items)
|
||||
@@ -144,6 +162,7 @@ public class SurrealOplogStore : OplogStore
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task MergeAsync(IEnumerable<OplogEntry> items, CancellationToken cancellationToken = default)
|
||||
{
|
||||
foreach (var item in items)
|
||||
@@ -155,6 +174,7 @@ public class SurrealOplogStore : OplogStore
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void InitializeVectorClock()
|
||||
{
|
||||
if (_vectorClock.IsInitialized) return;
|
||||
@@ -206,6 +226,7 @@ public class SurrealOplogStore : OplogStore
|
||||
_vectorClock.IsInitialized = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task InsertOplogEntryAsync(OplogEntry entry, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var existing = await FindByHashAsync(entry.Hash, cancellationToken);
|
||||
@@ -214,6 +235,7 @@ public class SurrealOplogStore : OplogStore
|
||||
await UpsertAsync(entry, SurrealStoreRecordIds.Oplog(entry.Hash), cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task<string?> QueryLastHashForNodeAsync(string nodeId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -226,6 +248,7 @@ public class SurrealOplogStore : OplogStore
|
||||
return lastEntry?.Hash;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task<(long Wall, int Logic)?> QueryLastHashTimestampFromOplogAsync(string hash,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,12 @@ public class SurrealPeerConfigurationStore : PeerConfigurationStore
|
||||
private readonly ICBDDCSurrealSchemaInitializer _schemaInitializer;
|
||||
private readonly ISurrealDbClient _surrealClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SurrealPeerConfigurationStore"/> class.
|
||||
/// </summary>
|
||||
/// <param name="surrealEmbeddedClient">The embedded SurrealDB client.</param>
|
||||
/// <param name="schemaInitializer">The schema initializer.</param>
|
||||
/// <param name="logger">The logger instance.</param>
|
||||
public SurrealPeerConfigurationStore(
|
||||
ICBDDCSurrealEmbeddedClient surrealEmbeddedClient,
|
||||
ICBDDCSurrealSchemaInitializer schemaInitializer,
|
||||
@@ -23,6 +29,7 @@ public class SurrealPeerConfigurationStore : PeerConfigurationStore
|
||||
_logger = logger ?? NullLogger<SurrealPeerConfigurationStore>.Instance;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<RemotePeerConfiguration>> GetRemotePeersAsync(
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -30,6 +37,7 @@ public class SurrealPeerConfigurationStore : PeerConfigurationStore
|
||||
return all.Select(p => p.ToDomain()).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<RemotePeerConfiguration?> GetRemotePeerAsync(string nodeId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -37,6 +45,7 @@ public class SurrealPeerConfigurationStore : PeerConfigurationStore
|
||||
return existing?.ToDomain();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task RemoveRemotePeerAsync(string nodeId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await EnsureReadyAsync(cancellationToken);
|
||||
@@ -52,6 +61,7 @@ public class SurrealPeerConfigurationStore : PeerConfigurationStore
|
||||
_logger.LogInformation("Removed remote peer configuration: {NodeId}", nodeId);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task SaveRemotePeerAsync(RemotePeerConfiguration peer,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -67,6 +77,7 @@ public class SurrealPeerConfigurationStore : PeerConfigurationStore
|
||||
_logger.LogInformation("Saved remote peer configuration: {NodeId} ({Type})", peer.NodeId, peer.Type);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task DropAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
@@ -76,6 +87,7 @@ public class SurrealPeerConfigurationStore : PeerConfigurationStore
|
||||
_logger.LogInformation("Peer configuration store dropped successfully.");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<RemotePeerConfiguration>> ExportAsync(
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
@@ -15,6 +15,12 @@ public class SurrealPeerOplogConfirmationStore : PeerOplogConfirmationStore
|
||||
private readonly ICBDDCSurrealSchemaInitializer _schemaInitializer;
|
||||
private readonly ISurrealDbClient _surrealClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SurrealPeerOplogConfirmationStore"/> class.
|
||||
/// </summary>
|
||||
/// <param name="surrealEmbeddedClient">Embedded Surreal client wrapper.</param>
|
||||
/// <param name="schemaInitializer">Schema initializer.</param>
|
||||
/// <param name="logger">Optional logger.</param>
|
||||
public SurrealPeerOplogConfirmationStore(
|
||||
ICBDDCSurrealEmbeddedClient surrealEmbeddedClient,
|
||||
ICBDDCSurrealSchemaInitializer schemaInitializer,
|
||||
@@ -26,6 +32,7 @@ public class SurrealPeerOplogConfirmationStore : PeerOplogConfirmationStore
|
||||
_logger = logger ?? NullLogger<SurrealPeerOplogConfirmationStore>.Instance;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task EnsurePeerRegisteredAsync(
|
||||
string peerNodeId,
|
||||
string address,
|
||||
@@ -68,6 +75,7 @@ public class SurrealPeerOplogConfirmationStore : PeerOplogConfirmationStore
|
||||
await UpsertAsync(existing, recordId, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task UpdateConfirmationAsync(
|
||||
string peerNodeId,
|
||||
string sourceNodeId,
|
||||
@@ -118,6 +126,7 @@ public class SurrealPeerOplogConfirmationStore : PeerOplogConfirmationStore
|
||||
await UpsertAsync(existing, recordId, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<PeerOplogConfirmation>> GetConfirmationsAsync(
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -128,6 +137,7 @@ public class SurrealPeerOplogConfirmationStore : PeerOplogConfirmationStore
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<PeerOplogConfirmation>> GetConfirmationsForPeerAsync(
|
||||
string peerNodeId,
|
||||
CancellationToken cancellationToken = default)
|
||||
@@ -143,6 +153,7 @@ public class SurrealPeerOplogConfirmationStore : PeerOplogConfirmationStore
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task RemovePeerTrackingAsync(string peerNodeId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(peerNodeId))
|
||||
@@ -167,6 +178,7 @@ public class SurrealPeerOplogConfirmationStore : PeerOplogConfirmationStore
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<string>> GetActiveTrackedPeersAsync(
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -178,18 +190,21 @@ public class SurrealPeerOplogConfirmationStore : PeerOplogConfirmationStore
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task DropAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await EnsureReadyAsync(cancellationToken);
|
||||
await _surrealClient.Delete(CBDDCSurrealSchemaNames.PeerOplogConfirmationsTable, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<PeerOplogConfirmation>> ExportAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var all = await SelectAllAsync(cancellationToken);
|
||||
return all.Select(c => c.ToDomain()).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task ImportAsync(IEnumerable<PeerOplogConfirmation> items,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -202,6 +217,7 @@ public class SurrealPeerOplogConfirmationStore : PeerOplogConfirmationStore
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task MergeAsync(IEnumerable<PeerOplogConfirmation> items,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,12 @@ internal static class SurrealShowChangesCborDecoder
|
||||
{
|
||||
private static readonly string[] PutChangeKinds = ["create", "update", "upsert", "insert", "set", "replace"];
|
||||
|
||||
/// <summary>
|
||||
/// Decodes change rows returned by a SurrealDB show changes query.
|
||||
/// </summary>
|
||||
/// <param name="rows">The CBOR rows to decode.</param>
|
||||
/// <param name="expectedTableName">The expected table name used to validate row identifiers.</param>
|
||||
/// <returns>The decoded set of change rows.</returns>
|
||||
public static IReadOnlyList<SurrealPolledChangeRow> DecodeRows(
|
||||
IEnumerable<CborObject> rows,
|
||||
string expectedTableName)
|
||||
|
||||
@@ -12,6 +12,12 @@ public class SurrealSnapshotMetadataStore : SnapshotMetadataStore
|
||||
private readonly ICBDDCSurrealSchemaInitializer _schemaInitializer;
|
||||
private readonly ISurrealDbClient _surrealClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SurrealSnapshotMetadataStore" /> class.
|
||||
/// </summary>
|
||||
/// <param name="surrealEmbeddedClient">The Surreal embedded client provider.</param>
|
||||
/// <param name="schemaInitializer">The schema initializer used to prepare storage.</param>
|
||||
/// <param name="logger">The optional logger instance.</param>
|
||||
public SurrealSnapshotMetadataStore(
|
||||
ICBDDCSurrealEmbeddedClient surrealEmbeddedClient,
|
||||
ICBDDCSurrealSchemaInitializer schemaInitializer,
|
||||
@@ -23,18 +29,21 @@ public class SurrealSnapshotMetadataStore : SnapshotMetadataStore
|
||||
_logger = logger ?? NullLogger<SurrealSnapshotMetadataStore>.Instance;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task DropAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await EnsureReadyAsync(cancellationToken);
|
||||
await _surrealClient.Delete(CBDDCSurrealSchemaNames.SnapshotMetadataTable, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<SnapshotMetadata>> ExportAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var all = await SelectAllAsync(cancellationToken);
|
||||
return all.Select(m => m.ToDomain()).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<SnapshotMetadata?> GetSnapshotMetadataAsync(string nodeId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -42,12 +51,14 @@ public class SurrealSnapshotMetadataStore : SnapshotMetadataStore
|
||||
return existing?.ToDomain();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<string?> GetSnapshotHashAsync(string nodeId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var existing = await FindByNodeIdAsync(nodeId, cancellationToken);
|
||||
return existing?.Hash;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task ImportAsync(IEnumerable<SnapshotMetadata> items,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -59,6 +70,7 @@ public class SurrealSnapshotMetadataStore : SnapshotMetadataStore
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task InsertSnapshotMetadataAsync(SnapshotMetadata metadata,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -67,6 +79,7 @@ public class SurrealSnapshotMetadataStore : SnapshotMetadataStore
|
||||
await UpsertAsync(metadata, recordId, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task MergeAsync(IEnumerable<SnapshotMetadata> items, CancellationToken cancellationToken = default)
|
||||
{
|
||||
foreach (var metadata in items)
|
||||
@@ -88,6 +101,7 @@ public class SurrealSnapshotMetadataStore : SnapshotMetadataStore
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task UpdateSnapshotMetadataAsync(SnapshotMetadata existingMeta,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -98,6 +112,7 @@ public class SurrealSnapshotMetadataStore : SnapshotMetadataStore
|
||||
await UpsertAsync(existingMeta, recordId, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<IEnumerable<SnapshotMetadata>> GetAllSnapshotMetadataAsync(
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
@@ -11,11 +11,22 @@ namespace ZB.MOM.WW.CBDDC.Persistence.Surreal;
|
||||
|
||||
internal static class SurrealStoreRecordIds
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates the record identifier for an oplog entry.
|
||||
/// </summary>
|
||||
/// <param name="hash">The oplog entry hash.</param>
|
||||
/// <returns>The SurrealDB record identifier.</returns>
|
||||
public static RecordId Oplog(string hash)
|
||||
{
|
||||
return RecordId.From(CBDDCSurrealSchemaNames.OplogEntriesTable, hash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the record identifier for document metadata.
|
||||
/// </summary>
|
||||
/// <param name="collection">The document collection name.</param>
|
||||
/// <param name="key">The document key.</param>
|
||||
/// <returns>The SurrealDB record identifier.</returns>
|
||||
public static RecordId DocumentMetadata(string collection, string key)
|
||||
{
|
||||
return RecordId.From(
|
||||
@@ -23,16 +34,32 @@ internal static class SurrealStoreRecordIds
|
||||
CompositeKey("docmeta", collection, key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the record identifier for snapshot metadata.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identifier.</param>
|
||||
/// <returns>The SurrealDB record identifier.</returns>
|
||||
public static RecordId SnapshotMetadata(string nodeId)
|
||||
{
|
||||
return RecordId.From(CBDDCSurrealSchemaNames.SnapshotMetadataTable, nodeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the record identifier for a remote peer configuration.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The peer node identifier.</param>
|
||||
/// <returns>The SurrealDB record identifier.</returns>
|
||||
public static RecordId RemotePeer(string nodeId)
|
||||
{
|
||||
return RecordId.From(CBDDCSurrealSchemaNames.RemotePeerConfigurationsTable, nodeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the record identifier for a peer oplog confirmation.
|
||||
/// </summary>
|
||||
/// <param name="peerNodeId">The peer node identifier.</param>
|
||||
/// <param name="sourceNodeId">The source node identifier.</param>
|
||||
/// <returns>The SurrealDB record identifier.</returns>
|
||||
public static RecordId PeerOplogConfirmation(string peerNodeId, string sourceNodeId)
|
||||
{
|
||||
return RecordId.From(
|
||||
@@ -49,114 +76,212 @@ internal static class SurrealStoreRecordIds
|
||||
|
||||
internal sealed class SurrealOplogRecord : Record
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the collection name.
|
||||
/// </summary>
|
||||
[JsonPropertyName("collection")]
|
||||
public string Collection { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the document key.
|
||||
/// </summary>
|
||||
[JsonPropertyName("key")]
|
||||
public string Key { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the operation type value.
|
||||
/// </summary>
|
||||
[JsonPropertyName("operation")]
|
||||
public int Operation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the serialized payload JSON.
|
||||
/// </summary>
|
||||
[JsonPropertyName("payloadJson")]
|
||||
public string PayloadJson { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp physical time.
|
||||
/// </summary>
|
||||
[JsonPropertyName("timestampPhysicalTime")]
|
||||
public long TimestampPhysicalTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp logical counter.
|
||||
/// </summary>
|
||||
[JsonPropertyName("timestampLogicalCounter")]
|
||||
public int TimestampLogicalCounter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp node identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("timestampNodeId")]
|
||||
public string TimestampNodeId { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the entry hash.
|
||||
/// </summary>
|
||||
[JsonPropertyName("hash")]
|
||||
public string Hash { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the previous entry hash.
|
||||
/// </summary>
|
||||
[JsonPropertyName("previousHash")]
|
||||
public string PreviousHash { get; set; } = "";
|
||||
}
|
||||
|
||||
internal sealed class SurrealDocumentMetadataRecord : Record
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the collection name.
|
||||
/// </summary>
|
||||
[JsonPropertyName("collection")]
|
||||
public string Collection { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the document key.
|
||||
/// </summary>
|
||||
[JsonPropertyName("key")]
|
||||
public string Key { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HLC physical time.
|
||||
/// </summary>
|
||||
[JsonPropertyName("hlcPhysicalTime")]
|
||||
public long HlcPhysicalTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HLC logical counter.
|
||||
/// </summary>
|
||||
[JsonPropertyName("hlcLogicalCounter")]
|
||||
public int HlcLogicalCounter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HLC node identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("hlcNodeId")]
|
||||
public string HlcNodeId { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the document is deleted.
|
||||
/// </summary>
|
||||
[JsonPropertyName("isDeleted")]
|
||||
public bool IsDeleted { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class SurrealRemotePeerRecord : Record
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the peer node identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("nodeId")]
|
||||
public string NodeId { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the peer network address.
|
||||
/// </summary>
|
||||
[JsonPropertyName("address")]
|
||||
public string Address { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the peer type value.
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
public int Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the peer is enabled.
|
||||
/// </summary>
|
||||
[JsonPropertyName("isEnabled")]
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the serialized list of collection interests.
|
||||
/// </summary>
|
||||
[JsonPropertyName("interestsJson")]
|
||||
public string InterestsJson { get; set; } = "";
|
||||
}
|
||||
|
||||
internal sealed class SurrealPeerOplogConfirmationRecord : Record
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the peer node identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("peerNodeId")]
|
||||
public string PeerNodeId { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the source node identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("sourceNodeId")]
|
||||
public string SourceNodeId { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the confirmed wall clock component.
|
||||
/// </summary>
|
||||
[JsonPropertyName("confirmedWall")]
|
||||
public long ConfirmedWall { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the confirmed logical component.
|
||||
/// </summary>
|
||||
[JsonPropertyName("confirmedLogic")]
|
||||
public int ConfirmedLogic { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the confirmed hash.
|
||||
/// </summary>
|
||||
[JsonPropertyName("confirmedHash")]
|
||||
public string ConfirmedHash { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the last confirmation time in Unix milliseconds.
|
||||
/// </summary>
|
||||
[JsonPropertyName("lastConfirmedUtcMs")]
|
||||
public long LastConfirmedUtcMs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the confirmation is active.
|
||||
/// </summary>
|
||||
[JsonPropertyName("isActive")]
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class SurrealSnapshotMetadataRecord : Record
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the node identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("nodeId")]
|
||||
public string NodeId { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp physical time.
|
||||
/// </summary>
|
||||
[JsonPropertyName("timestampPhysicalTime")]
|
||||
public long TimestampPhysicalTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp logical counter.
|
||||
/// </summary>
|
||||
[JsonPropertyName("timestampLogicalCounter")]
|
||||
public int TimestampLogicalCounter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the snapshot hash.
|
||||
/// </summary>
|
||||
[JsonPropertyName("hash")]
|
||||
public string Hash { get; set; } = "";
|
||||
}
|
||||
|
||||
internal static class SurrealStoreRecordMappers
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps a domain oplog entry to a SurrealDB record.
|
||||
/// </summary>
|
||||
/// <param name="entry">The domain oplog entry.</param>
|
||||
/// <returns>The SurrealDB oplog record.</returns>
|
||||
public static SurrealOplogRecord ToSurrealRecord(this OplogEntry entry)
|
||||
{
|
||||
return new SurrealOplogRecord
|
||||
@@ -173,6 +298,11 @@ internal static class SurrealStoreRecordMappers
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a SurrealDB oplog record to a domain oplog entry.
|
||||
/// </summary>
|
||||
/// <param name="record">The SurrealDB oplog record.</param>
|
||||
/// <returns>The domain oplog entry.</returns>
|
||||
public static OplogEntry ToDomain(this SurrealOplogRecord record)
|
||||
{
|
||||
JsonElement? payload = null;
|
||||
@@ -189,6 +319,11 @@ internal static class SurrealStoreRecordMappers
|
||||
record.Hash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps domain document metadata to a SurrealDB record.
|
||||
/// </summary>
|
||||
/// <param name="metadata">The domain document metadata.</param>
|
||||
/// <returns>The SurrealDB document metadata record.</returns>
|
||||
public static SurrealDocumentMetadataRecord ToSurrealRecord(this DocumentMetadata metadata)
|
||||
{
|
||||
return new SurrealDocumentMetadataRecord
|
||||
@@ -202,6 +337,11 @@ internal static class SurrealStoreRecordMappers
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a SurrealDB document metadata record to domain document metadata.
|
||||
/// </summary>
|
||||
/// <param name="record">The SurrealDB document metadata record.</param>
|
||||
/// <returns>The domain document metadata.</returns>
|
||||
public static DocumentMetadata ToDomain(this SurrealDocumentMetadataRecord record)
|
||||
{
|
||||
return new DocumentMetadata(
|
||||
@@ -211,6 +351,11 @@ internal static class SurrealStoreRecordMappers
|
||||
record.IsDeleted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a domain remote peer configuration to a SurrealDB record.
|
||||
/// </summary>
|
||||
/// <param name="peer">The domain remote peer configuration.</param>
|
||||
/// <returns>The SurrealDB remote peer record.</returns>
|
||||
public static SurrealRemotePeerRecord ToSurrealRecord(this RemotePeerConfiguration peer)
|
||||
{
|
||||
return new SurrealRemotePeerRecord
|
||||
@@ -225,6 +370,11 @@ internal static class SurrealStoreRecordMappers
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a SurrealDB remote peer record to a domain remote peer configuration.
|
||||
/// </summary>
|
||||
/// <param name="record">The SurrealDB remote peer record.</param>
|
||||
/// <returns>The domain remote peer configuration.</returns>
|
||||
public static RemotePeerConfiguration ToDomain(this SurrealRemotePeerRecord record)
|
||||
{
|
||||
var result = new RemotePeerConfiguration
|
||||
@@ -242,6 +392,11 @@ internal static class SurrealStoreRecordMappers
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a domain peer oplog confirmation to a SurrealDB record.
|
||||
/// </summary>
|
||||
/// <param name="confirmation">The domain peer oplog confirmation.</param>
|
||||
/// <returns>The SurrealDB peer oplog confirmation record.</returns>
|
||||
public static SurrealPeerOplogConfirmationRecord ToSurrealRecord(this PeerOplogConfirmation confirmation)
|
||||
{
|
||||
return new SurrealPeerOplogConfirmationRecord
|
||||
@@ -256,6 +411,11 @@ internal static class SurrealStoreRecordMappers
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a SurrealDB peer oplog confirmation record to a domain model.
|
||||
/// </summary>
|
||||
/// <param name="record">The SurrealDB peer oplog confirmation record.</param>
|
||||
/// <returns>The domain peer oplog confirmation.</returns>
|
||||
public static PeerOplogConfirmation ToDomain(this SurrealPeerOplogConfirmationRecord record)
|
||||
{
|
||||
return new PeerOplogConfirmation
|
||||
@@ -270,6 +430,11 @@ internal static class SurrealStoreRecordMappers
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps domain snapshot metadata to a SurrealDB record.
|
||||
/// </summary>
|
||||
/// <param name="metadata">The domain snapshot metadata.</param>
|
||||
/// <returns>The SurrealDB snapshot metadata record.</returns>
|
||||
public static SurrealSnapshotMetadataRecord ToSurrealRecord(this SnapshotMetadata metadata)
|
||||
{
|
||||
return new SurrealSnapshotMetadataRecord
|
||||
@@ -281,6 +446,11 @@ internal static class SurrealStoreRecordMappers
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a SurrealDB snapshot metadata record to a domain model.
|
||||
/// </summary>
|
||||
/// <param name="record">The SurrealDB snapshot metadata record.</param>
|
||||
/// <returns>The domain snapshot metadata.</returns>
|
||||
public static SnapshotMetadata ToDomain(this SurrealSnapshotMetadataRecord record)
|
||||
{
|
||||
return new SnapshotMetadata
|
||||
|
||||
Reference in New Issue
Block a user