Merge branch 'dev' into claire/cnx-849

This commit is contained in:
Claire Kuang
2024-12-03 22:18:24 +00:00
committed by GitHub
23 changed files with 83 additions and 123 deletions
@@ -1,5 +1,3 @@
#nullable disable
using System.Reflection;
using GraphQL.Client.Abstractions.Utilities;
using Speckle.Newtonsoft.Json;
@@ -9,7 +7,7 @@ namespace Speckle.Sdk.Api.GraphQL.Serializer;
internal class ConstantCaseEnumConverter : StringEnumConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value == null)
{
@@ -18,7 +16,7 @@ internal class ConstantCaseEnumConverter : StringEnumConverter
else
{
var enumString = ((Enum)value).ToString("G");
var memberName = value
string? memberName = value
.GetType()
.GetMember(enumString, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public)
.FirstOrDefault()
@@ -34,7 +32,9 @@ internal class ConstantCaseEnumConverter : StringEnumConverter
}
else
{
#pragma warning disable CS8604 // Possible null reference argument. //never null?
writer.WriteValue(memberName.ToConstantCase());
#pragma warning restore CS8604 // Possible null reference argument.
}
}
}
@@ -1,4 +1,3 @@
#nullable disable
using System.Diagnostics.CodeAnalysis;
using GraphQL;
using Speckle.Newtonsoft.Json;
@@ -8,7 +7,7 @@ namespace Speckle.Sdk.Api.GraphQL.Serializer;
internal sealed class MapConverter : JsonConverter<Map>
{
public override void WriteJson(JsonWriter writer, Map value, JsonSerializer serializer)
public override void WriteJson(JsonWriter writer, Map? value, JsonSerializer serializer)
{
throw new NotImplementedException(
"This converter currently is only intended to be used to read a JSON object into a strongly-typed representation."
@@ -18,7 +17,7 @@ internal sealed class MapConverter : JsonConverter<Map>
public override Map ReadJson(
JsonReader reader,
Type objectType,
Map existingValue,
Map? existingValue,
bool hasExistingValue,
JsonSerializer serializer
)
@@ -39,16 +38,23 @@ internal sealed class MapConverter : JsonConverter<Map>
)]
private object ReadToken(JToken token)
{
return token switch
switch (token)
{
JObject jObject => ReadDictionary(jObject, new Dictionary<string, object>()),
JArray jArray => ReadArray(jArray).ToList(),
JValue jValue => jValue.Value,
JConstructor => throw new ArgumentOutOfRangeException(nameof(token), "cannot deserialize a JSON constructor"),
JProperty => throw new ArgumentOutOfRangeException(nameof(token), "cannot deserialize a JSON property"),
JContainer => throw new ArgumentOutOfRangeException(nameof(token), "cannot deserialize a JSON comment"),
_ => throw new ArgumentOutOfRangeException(nameof(token), $"Invalid token type {token?.Type}"),
};
case JObject jObject:
return ReadDictionary(jObject, new Dictionary<string, object>());
case JArray jArray:
return ReadArray(jArray).ToList();
case JValue jValue:
return jValue.Value ?? string.Empty;
case JConstructor:
throw new ArgumentOutOfRangeException(nameof(token), "cannot deserialize a JSON constructor");
case JProperty:
throw new ArgumentOutOfRangeException(nameof(token), "cannot deserialize a JSON property");
case JContainer:
throw new ArgumentOutOfRangeException(nameof(token), "cannot deserialize a JSON comment");
default:
throw new ArgumentOutOfRangeException(nameof(token), $"Invalid token type {token?.Type}");
}
}
private Dictionary<string, object> ReadDictionary(JToken element, Dictionary<string, object> to)
@@ -1,10 +1,10 @@
#nullable disable
using System.Text;
using GraphQL;
using GraphQL.Client.Abstractions;
using GraphQL.Client.Abstractions.Websocket;
using Speckle.Newtonsoft.Json;
using Speckle.Newtonsoft.Json.Serialization;
using Speckle.Sdk.Common;
using Speckle.Sdk.Serialisation;
namespace Speckle.Sdk.Api.GraphQL.Serializer;
@@ -51,10 +51,9 @@ internal sealed class NewtonsoftJsonSerializer : IGraphQLWebsocketJsonSerializer
public GraphQLWebSocketResponse<TResponse> DeserializeToWebsocketResponse<TResponse>(byte[] bytes)
{
return JsonConvert.DeserializeObject<GraphQLWebSocketResponse<TResponse>>(
Encoding.UTF8.GetString(bytes),
JsonSerializerSettings
);
return JsonConvert
.DeserializeObject<GraphQLWebSocketResponse<TResponse>>(Encoding.UTF8.GetString(bytes), JsonSerializerSettings)
.NotNull();
}
public Task<GraphQLResponse<TResponse>> DeserializeFromUtf8StreamAsync<TResponse>(
@@ -79,6 +78,6 @@ internal sealed class NewtonsoftJsonSerializer : IGraphQLWebsocketJsonSerializer
using var sr = new StreamReader(stream);
using JsonReader reader = SpeckleObjectSerializerPool.Instance.GetJsonTextReader(sr);
var serializer = JsonSerializer.Create(serializerSettings);
return Task.FromResult(serializer.Deserialize<T>(reader));
return Task.FromResult(serializer.Deserialize<T>(reader) ?? throw new ArgumentException("Serialized data is null"));
}
}
+3 -4
View File
@@ -1,4 +1,3 @@
#nullable disable
using System.Runtime.InteropServices;
using Speckle.Sdk.Api.GraphQL.Models;
using Speckle.Sdk.Helpers;
@@ -48,7 +47,7 @@ public class Account : IEquatable<Account>
private static string CleanURL(string server)
{
if (Uri.TryCreate(server, UriKind.Absolute, out Uri newUri))
if (Uri.TryCreate(server, UriKind.Absolute, out Uri? newUri))
{
server = newUri.Authority;
}
@@ -77,12 +76,12 @@ public class Account : IEquatable<Account>
return $"Account ({userInfo.email} | {serverInfo.url})";
}
public bool Equals(Account other)
public bool Equals(Account? other)
{
return other is not null && other.userInfo.email == userInfo.email && other.serverInfo.url == serverInfo.url;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Account acc && Equals(acc);
}
@@ -248,7 +248,7 @@ public class AccountManager(
account.serverInfo.frontend2 = true;
// setting the id to null will force it to be recreated
account.id = null;
account.id = null!; //TODO this is gross so remove when id is nullable
RemoveAccount(id);
_accountStorage.SaveObject(account.id.NotNull(), JsonConvert.SerializeObject(account));
+3 -4
View File
@@ -1,4 +1,3 @@
#nullable disable
namespace Speckle.Sdk.Host;
[AttributeUsage(AttributeTargets.Constructor)]
@@ -7,7 +6,7 @@ public sealed class SchemaInfoAttribute : Attribute
public SchemaInfoAttribute(string name, string description)
: this(name, description, null, null) { }
public SchemaInfoAttribute(string name, string description, string category, string subcategory)
public SchemaInfoAttribute(string name, string description, string? category, string? subcategory)
{
Name = name;
Description = description;
@@ -15,9 +14,9 @@ public sealed class SchemaInfoAttribute : Attribute
Subcategory = subcategory;
}
public string Subcategory { get; }
public string? Subcategory { get; }
public string Category { get; }
public string? Category { get; }
public string Description { get; }
+2 -5
View File
@@ -1,4 +1,3 @@
#nullable disable
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
@@ -24,15 +23,13 @@ namespace Speckle.Sdk.Models;
[SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Serialized property names are camelCase by design")]
public class Base : DynamicBase, ISpeckleObject
{
private string _type;
private string? _type;
/// <summary>
/// A speckle object's id is an unique hash based on its properties. <b>NOTE: this field will be null unless the object was deserialised from a source. Use the <see cref="GetId"/> function to get it.</b>
/// </summary>
[SchemaIgnore]
public virtual string id { get; set; }
#nullable enable //Starting nullability syntax here so that `id` null oblivious,
public virtual string? id { get; set; }
/// <summary>
/// Secondary, ideally host application driven, object identifier.
+5 -5
View File
@@ -1,5 +1,4 @@
#nullable disable
using System.Runtime.Serialization;
using System.Runtime.Serialization;
using Speckle.Newtonsoft.Json;
namespace Speckle.Sdk.Models;
@@ -38,13 +37,13 @@ public class Blob : Base
/// <summary>
/// For blobs, the id is the same as the file hash. Please note, when deserialising, the id will be set from the original hash generated on sending.
/// </summary>
public override string id
public override string? id
{
get => GetFileHash();
set => base.id = value;
}
public string GetFileHash()
public string? GetFileHash()
{
if ((_isHashExpired || _hash == null) && filePath != null)
{
@@ -63,6 +62,7 @@ public class Blob : Base
public string GetLocalDestinationPath(string blobStorageFolder)
{
var fileName = Path.GetFileName(filePath);
return Path.Combine(blobStorageFolder, $"{id[..10]}-{fileName}");
var x = id ?? throw new ArgumentException("id is empty");
return Path.Combine(blobStorageFolder, $"{x[..10]}-{fileName}");
}
}
@@ -1,5 +1,6 @@
using System.Collections;
using System.Diagnostics.Contracts;
using Speckle.Sdk.Common;
using Speckle.Sdk.Models.Collections;
namespace Speckle.Sdk.Models.Extensions;
@@ -31,7 +32,7 @@ public static class BaseExtensions
root,
b =>
{
if (!cache.Add(b.id))
if (!cache.Add(b.id.NotNull()))
{
return true;
}
@@ -42,7 +43,7 @@ public static class BaseExtensions
foreach (var b in traversal)
{
if (!cache.Contains(b.id))
if (!cache.Contains(b.id.NotNull()))
{
yield return b;
}
+1 -4
View File
@@ -2,10 +2,7 @@
public interface ISpeckleObject
{
#nullable disable
public string id { get; }
#nullable enable //Starting nullability syntax here so that `id` null oblivious,
public string? id { get; }
public string? applicationId { get; }
@@ -362,7 +362,7 @@ public class SpeckleObjectSerializer
}
else
{
id = new Id(((Blob)baseObj).id);
id = new Id(((Blob)baseObj).id.NotNull());
}
writer.WritePropertyName("id");
writer.WriteValue(id.Value);
@@ -20,7 +20,6 @@ public class ObjectSerializer : IObjectSerializer
{
private HashSet<object> _parentObjects = new();
private readonly Dictionary<Id, int> _currentClosures = new();
private readonly IDictionary<Base, CacheInfo> _baseCache;
private readonly bool _trackDetachedChildren;
private readonly IBasePropertyGatherer _propertyGatherer;
@@ -41,12 +40,10 @@ public class ObjectSerializer : IObjectSerializer
/// <param name="cancellationToken"></param>
public ObjectSerializer(
IBasePropertyGatherer propertyGatherer,
IDictionary<Base, CacheInfo> baseCache,
bool trackDetachedChildren = false,
CancellationToken cancellationToken = default
)
{
_baseCache = baseCache;
_propertyGatherer = propertyGatherer;
_cancellationToken = cancellationToken;
_trackDetachedChildren = trackDetachedChildren;
@@ -69,7 +66,6 @@ public class ObjectSerializer : IObjectSerializer
{
throw new SpeckleSerializeException($"Failed to extract (pre-serialize) properties from the {baseObj}", ex);
}
_baseCache[baseObj] = new(item.Item2, _currentClosures);
yield return (item.Item1, item.Item2);
foreach (var chunk in _chunks)
{
@@ -232,26 +228,13 @@ public class ObjectSerializer : IObjectSerializer
return null;
}
Closures childClosures;
Id id;
Json json;
if (_baseCache.TryGetValue(baseObj, out var info))
{
id = new Id(baseObj.id);
childClosures = info.Closures;
json = info.Json;
MergeClosures(_currentClosures, childClosures);
}
else
{
childClosures = isRoot || inheritedDetachInfo.IsDetachable ? _currentClosures : [];
var sb = Pools.StringBuilders.Get();
using var writer = new StringWriter(sb);
using var jsonWriter = SpeckleObjectSerializerPool.Instance.GetJsonTextWriter(writer);
id = SerializeBaseObject(baseObj, jsonWriter, childClosures);
json = new Json(writer.ToString());
Pools.StringBuilders.Return(sb);
}
var childClosures = isRoot || inheritedDetachInfo.IsDetachable ? _currentClosures : [];
var sb = Pools.StringBuilders.Get();
using var writer = new StringWriter(sb);
using var jsonWriter = SpeckleObjectSerializerPool.Instance.GetJsonTextWriter(writer);
var id = SerializeBaseObject(baseObj, jsonWriter, childClosures);
var json = new Json(writer.ToString());
Pools.StringBuilders.Return(sb);
_parentObjects.Remove(baseObj);
@@ -311,7 +294,7 @@ public class ObjectSerializer : IObjectSerializer
}
else
{
id = new Id(((Blob)baseObj).id);
id = new Id(((Blob)baseObj).id.NotNull());
}
writer.WritePropertyName("id");
writer.WriteValue(id.Value);
@@ -1,11 +1,10 @@
using Speckle.InterfaceGenerator;
using Speckle.Sdk.Models;
namespace Speckle.Sdk.Serialisation.V2.Send;
[GenerateAutoInterface]
public class ObjectSerializerFactory(IBasePropertyGatherer propertyGatherer) : IObjectSerializerFactory
{
public IObjectSerializer Create(IDictionary<Base, CacheInfo> baseCache, CancellationToken cancellationToken) =>
new ObjectSerializer(propertyGatherer, baseCache, true, cancellationToken);
public IObjectSerializer Create(CancellationToken cancellationToken) =>
new ObjectSerializer(propertyGatherer, true, cancellationToken);
}
@@ -9,7 +9,7 @@ using Speckle.Sdk.Transports;
namespace Speckle.Sdk.Serialisation.V2.Send;
public record SerializeProcessOptions(bool SkipCacheRead, bool SkipCacheWrite, bool SkipServer, bool CacheBases);
public record SerializeProcessOptions(bool SkipCacheRead, bool SkipCacheWrite, bool SkipServer);
public readonly record struct SerializeProcessResults(
string RootId,
@@ -26,11 +26,8 @@ public class SerializeProcess(
SerializeProcessOptions? options = null
) : ChannelSaver, ISerializeProcess
{
private readonly SerializeProcessOptions _options = options ?? new(false, false, false, true);
private readonly SerializeProcessOptions _options = options ?? new(false, false, false);
private readonly ConcurrentDictionary<Id, Json> _jsonCache = new();
private readonly IDictionary<Base, CacheInfo> _baseCache =
options?.CacheBases ?? true ? new ConcurrentDictionary<Base, CacheInfo>() : new EmptyDictionary<Base, CacheInfo>();
private readonly ConcurrentDictionary<Id, ObjectReference> _objectReferences = new();
private long _totalFound;
@@ -44,7 +41,7 @@ public class SerializeProcess(
var channelTask = Start(cancellationToken);
await Traverse(root, true, cancellationToken).ConfigureAwait(false);
await channelTask.ConfigureAwait(false);
return new(root.id, _objectReferences.Freeze());
return new(root.id.NotNull(), _objectReferences.Freeze());
}
private async Task Traverse(Base obj, bool isEnd, CancellationToken cancellationToken)
@@ -110,7 +107,7 @@ public class SerializeProcess(
}
if (id is null || !_jsonCache.TryGetValue(id.Value, out var json))
{
var serializer2 = objectSerializerFactory.Create(_baseCache, cancellationToken);
var serializer2 = objectSerializerFactory.Create(cancellationToken);
var items = serializer2.Serialize(obj).ToList();
foreach (var kvp in serializer2.ObjectReferences)
{