Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed code factor quality issues #558

Merged
merged 4 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 50 additions & 13 deletions src/PinguApps.Appwrite.Shared/Converters/AttributeJsonConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,73 @@ public class AttributeJsonConverter : JsonConverter<Attribute>
public override Attribute? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using var jsonDoc = JsonDocument.ParseValue(ref reader);

var jsonObject = jsonDoc.RootElement;

var attributeType = ResolveAttributeType(jsonObject);

return DeserializeAttribute(jsonObject, attributeType, options);
}

private static Type ResolveAttributeType(JsonElement jsonObject)
{
var type = GetRequiredTypeProperty(jsonObject);
var format = GetOptionalFormatProperty(jsonObject);

return DetermineAttributeType(type, format, jsonObject);
}

private static string GetRequiredTypeProperty(JsonElement jsonObject)
{
if (!jsonObject.TryGetProperty("type", out var typeProperty))
{
throw new JsonException("Missing `Type` property");
}

var type = typeProperty.GetString();
return typeProperty.GetString()!;
}

private static string? GetOptionalFormatProperty(JsonElement jsonObject)
{
jsonObject.TryGetProperty("format", out var formatProperty);
var format = formatProperty.ValueKind == JsonValueKind.String ? formatProperty.GetString() : null;

var derivedType = type switch
return formatProperty.ValueKind is JsonValueKind.String ? formatProperty.GetString() : null;
}

private static Type DetermineAttributeType(string type, string? format, JsonElement jsonObject)
{
return type switch
{
"boolean" => typeof(AttributeBoolean),
"integer" => typeof(AttributeInteger),
"double" => typeof(AttributeFloat),
"datetime" => typeof(AttributeDatetime),
"string" => format switch
{
"email" => typeof(AttributeEmail),
"url" => typeof(AttributeUrl),
"ip" => typeof(AttributeIp),
"enum" => typeof(AttributeEnum),
null or "" => jsonObject.TryGetProperty("relatedCollection", out _) ? typeof(AttributeRelationship) : typeof(AttributeString),
_ => throw new JsonException($"Unknown format: {format}")
},
"string" => ResolveStringAttributeType(format, jsonObject),
_ => throw new JsonException($"Unknown type: {type}")
};
}

private static Type ResolveStringAttributeType(string? format, JsonElement jsonObject)
{
return format switch
{
"email" => typeof(AttributeEmail),
"url" => typeof(AttributeUrl),
"ip" => typeof(AttributeIp),
"enum" => typeof(AttributeEnum),
null or "" => ResolveBasicStringAttributeType(jsonObject),
_ => throw new JsonException($"Unknown format: {format}")
};
}

private static Type ResolveBasicStringAttributeType(JsonElement jsonObject)
{
return jsonObject.TryGetProperty("relatedCollection", out _) ? typeof(AttributeRelationship) : typeof(AttributeString);
}

return (Attribute?)JsonSerializer.Deserialize(jsonObject.GetRawText(), derivedType, options);
private static Attribute? DeserializeAttribute(JsonElement jsonObject, Type attributeType, JsonSerializerOptions options)
{
return (Attribute?)JsonSerializer.Deserialize(jsonObject.GetRawText(), attributeType, options);
}

public override void Write(Utf8JsonWriter writer, Attribute value, JsonSerializerOptions options)
Expand Down
155 changes: 83 additions & 72 deletions src/PinguApps.Appwrite.Shared/Converters/DocumentGenericConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,102 +10,92 @@ namespace PinguApps.Appwrite.Shared.Converters;
public class DocumentGenericConverter<TData> : JsonConverter<Document<TData>>
where TData : class, new()
{
private class DocumentFields
{
public string? Id { get; set; }
public string? CollectionId { get; set; }
public string? DatabaseId { get; set; }
public DateTime? CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
public List<Permission>? Permissions { get; set; }
public Dictionary<string, object?> DataProperties { get; set; } = new();
}

public override Document<TData> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string? id = null;
string? collectionId = null;
string? databaseId = null;
DateTime? createdAt = null;
DateTime? updatedAt = null;
List<Permission>? permissions = null;
TData data = new();
ValidateStartObject(ref reader);

var dataProperties = new Dictionary<string, object?>();
var documentFields = ReadDocumentFields(ref reader, options);

var dateTimeConverter = new MultiFormatDateTimeConverter();
var permissionListConverter = new PermissionListConverter();
ValidateRequiredFields(documentFields);

var data = DeserializeCustomData(documentFields.DataProperties, options);

return new Document<TData>(documentFields.Id!, documentFields.CollectionId!, documentFields.DatabaseId!, documentFields.CreatedAt,
documentFields.UpdatedAt, documentFields.Permissions!, data);
}

private static void ValidateStartObject(ref Utf8JsonReader reader)
{
if (reader.TokenType is not JsonTokenType.StartObject)
{
throw new JsonException("Expected StartObject token");
}
}

private DocumentFields ReadDocumentFields(ref Utf8JsonReader reader, JsonSerializerOptions options)
{
var dateTimeConverter = new MultiFormatDateTimeConverter();
var permissionListConverter = new PermissionListConverter();
var fields = new DocumentFields();

while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
if (reader.TokenType is JsonTokenType.EndObject)
{
break;
}

var propertyName = reader.GetString()!;

reader.Read();

switch (propertyName)
{
case "$id":
id = reader.GetString();
break;
case "$collectionId":
collectionId = reader.GetString();
break;
case "$databaseId":
databaseId = reader.GetString();
break;
case "$createdAt":
createdAt = dateTimeConverter.Read(ref reader, typeof(DateTime), options);
break;
case "$updatedAt":
updatedAt = dateTimeConverter.Read(ref reader, typeof(DateTime), options);
break;
case "$permissions":
permissions = permissionListConverter.Read(ref reader, typeof(List<Permission>), options);
break;
default:
var value = ReadValue(ref reader, options);
dataProperties[propertyName] = value;
break;
}
}

if (id is null)
{
throw new JsonException("Unable to find a value for Id");
}

if (collectionId is null)
{
throw new JsonException("Unable to find a value for CollectionId");
}

if (databaseId is null)
{
throw new JsonException("Unable to find a value for DatabaseId");
ProcessProperty(ref reader, propertyName, fields, dateTimeConverter, permissionListConverter, options);
}

if (createdAt is null)
{
throw new JsonException("Unable to find a value for CreatedAt");
}

if (updatedAt is null)
{
throw new JsonException("Unable to find a value for UpdatedAt");
}
return fields;
}

if (permissions is null)
private static void ProcessProperty(ref Utf8JsonReader reader, string propertyName, DocumentFields fields,
MultiFormatDateTimeConverter dateTimeConverter, PermissionListConverter permissionListConverter, JsonSerializerOptions options)
{
switch (propertyName)
{
throw new JsonException("Unable to find a value for Permissions");
case "$id":
fields.Id = reader.GetString();
break;
case "$collectionId":
fields.CollectionId = reader.GetString();
break;
case "$databaseId":
fields.DatabaseId = reader.GetString();
break;
case "$createdAt":
fields.CreatedAt = dateTimeConverter.Read(ref reader, typeof(DateTime), options);
break;
case "$updatedAt":
fields.UpdatedAt = dateTimeConverter.Read(ref reader, typeof(DateTime), options);
break;
case "$permissions":
fields.Permissions = permissionListConverter.Read(ref reader, typeof(List<Permission>), options);
break;
default:
var value = ReadValue(ref reader, options);
fields.DataProperties[propertyName] = value;
break;
}

// Deserialize the remaining properties into TData
var dataJson = JsonSerializer.Serialize(dataProperties, options);
data = JsonSerializer.Deserialize<TData>(dataJson, options) ?? new TData();

return new Document<TData>(id, collectionId, databaseId, createdAt.Value, updatedAt.Value, permissions, data);
}

internal object? ReadValue(ref Utf8JsonReader reader, JsonSerializerOptions options)
internal static object? ReadValue(ref Utf8JsonReader reader, JsonSerializerOptions options)
{
switch (reader.TokenType)
{
Expand Down Expand Up @@ -143,7 +133,7 @@ public override Document<TData> Read(ref Utf8JsonReader reader, Type typeToConve
}
}

private IReadOnlyCollection<object?> ReadArray(ref Utf8JsonReader reader, JsonSerializerOptions options)
private static IReadOnlyCollection<object?> ReadArray(ref Utf8JsonReader reader, JsonSerializerOptions options)
{
var list = new List<object?>();

Expand All @@ -161,7 +151,7 @@ public override Document<TData> Read(ref Utf8JsonReader reader, Type typeToConve
return list;
}

private Dictionary<string, object?> ReadObject(ref Utf8JsonReader reader, JsonSerializerOptions options)
private static Dictionary<string, object?> ReadObject(ref Utf8JsonReader reader, JsonSerializerOptions options)
{
var dict = new Dictionary<string, object?>();

Expand All @@ -184,6 +174,27 @@ public override Document<TData> Read(ref Utf8JsonReader reader, Type typeToConve
return dict;
}

private static void ValidateRequiredFields(DocumentFields fields)
{
if (fields.Id is null)
throw new JsonException("Unable to find a value for Id");

if (fields.CollectionId is null)
throw new JsonException("Unable to find a value for CollectionId");

if (fields.DatabaseId is null)
throw new JsonException("Unable to find a value for DatabaseId");

if (fields.Permissions is null)
throw new JsonException("Unable to find a value for Permissions");
pingu2k4 marked this conversation as resolved.
Show resolved Hide resolved
}

private static TData DeserializeCustomData(Dictionary<string, object?> dataProperties, JsonSerializerOptions options)
{
var dataJson = JsonSerializer.Serialize(dataProperties, options);
return JsonSerializer.Deserialize<TData>(dataJson, options) ?? new TData();
}

public override void Write(Utf8JsonWriter writer, Document<TData> value, JsonSerializerOptions options)
{
writer.WriteStartObject();
Expand Down
Loading
Loading