Skip to content
Open
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
80 changes: 78 additions & 2 deletions src/SDK/Language/DotNet.php
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ public function getFilters(): array
}

/**
* get sub_scheme and property_name functions
* get sub_scheme, property_name and parse_value functions
* @return TwigFunction[]
*/
public function getFunctions(): array
Expand All @@ -494,7 +494,7 @@ public function getFunctions(): array
}

return $result;
}),
}, ['is_safe' => ['html']]),
new TwigFunction('property_name', function (array $definition, array $property) {
$name = $property['name'];
$name = \str_replace('$', '', $name);
Expand All @@ -504,6 +504,82 @@ public function getFunctions(): array
}
return $name;
}),
new TwigFunction('parse_value', function (array $property, string $mapAccess, string $v) {
$required = $property['required'] ?? false;

// Handle sub_schema
if (isset($property['sub_schema']) && !empty($property['sub_schema'])) {
$subSchema = \ucfirst($property['sub_schema']);

if ($property['type'] === 'array') {
$arraySource = $required
? "((IEnumerable<object>){$mapAccess})"
: "({$v} as IEnumerable<object>)?";
return "{$arraySource}.Select(it => {$subSchema}.From(map: (Dictionary<string, object>)it)).ToList()";
} else {
if ($required) {
return "{$subSchema}.From(map: (Dictionary<string, object>){$mapAccess})";
}
return "({$v} as Dictionary<string, object>) is { } obj ? {$subSchema}.From(map: obj) : null";
}
}

// Handle enum
if (isset($property['enum']) && !empty($property['enum'])) {
$enumName = $property['enumName'] ?? $property['name'];
$enumClass = \ucfirst($enumName);

if ($required) {
return "new {$enumClass}({$mapAccess}.ToString())";
}
return "{$v} == null ? null : new {$enumClass}({$v}.ToString())";
}

// Handle arrays
if ($property['type'] === 'array') {
$itemsType = $property['items']['type'] ?? 'object';
$src = $required ? $mapAccess : $v;
$arraySource = $required
? "((IEnumerable<object>){$src})"
: "({$src} as IEnumerable<object>)?";

$selectExpression = match ($itemsType) {
'string' => 'x.ToString()',
'integer' => 'Convert.ToInt64(x)',
'number' => 'Convert.ToDouble(x)',
'boolean' => '(bool)x',
default => 'x'
};

return "{$arraySource}.Select(x => {$selectExpression}).ToList()";
}

// Handle integer/number
if ($property['type'] === 'integer' || $property['type'] === 'number') {
$convertMethod = $property['type'] === 'integer' ? 'Int64' : 'Double';

if ($required) {
return "Convert.To{$convertMethod}({$mapAccess})";
}
return "{$v} == null ? null : Convert.To{$convertMethod}({$v})";
}

// Handle boolean
if ($property['type'] === 'boolean') {
$typeName = $this->getTypeName($property);

if ($required) {
return "({$typeName}){$mapAccess}";
}
return "({$typeName}?){$v}";
}

// Handle string type
if ($required) {
return "{$mapAccess}.ToString()";
}
return "{$v}?.ToString()";
}, ['is_safe' => ['html']]),
];
}

Expand Down
1 change: 1 addition & 0 deletions templates/dotnet/Package/Client.cs.twig
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ namespace {{ spec.title | caseUcfirst }}

foreach (var parameter in parameters)
{
if (parameter.Value == null) continue;
if (parameter.Key == "file")
{
var fileContent = parameters["file"] as MultipartFormDataContent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,60 @@ namespace {{ spec.title | caseUcfirst }}.Converters
{
public class ObjectToInferredTypesConverter : JsonConverter<object>
{
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
switch (reader.TokenType)
using (JsonDocument document = JsonDocument.ParseValue(ref reader))
{
case JsonTokenType.True:
return true;
case JsonTokenType.False:
return false;
case JsonTokenType.Number:
if (reader.TryGetInt64(out long l))
return ConvertElement(document.RootElement);
}
}

private object? ConvertElement(JsonElement element)
{
switch (element.ValueKind)
{
case JsonValueKind.Object:
var dictionary = new Dictionary<string, object?>();
foreach (var property in element.EnumerateObject())
{
return l;
dictionary[property.Name] = ConvertElement(property.Value);
}
return dictionary;

case JsonValueKind.Array:
var list = new List<object?>();
foreach (var item in element.EnumerateArray())
{
list.Add(ConvertElement(item));
}
return reader.GetDouble();
case JsonTokenType.String:
if (reader.TryGetDateTime(out DateTime datetime))
return list;

case JsonValueKind.String:
if (element.TryGetDateTime(out DateTime datetime))
{
return datetime;
}
return reader.GetString()!;
case JsonTokenType.StartObject:
return JsonSerializer.Deserialize<Dictionary<string, object>>(ref reader, options)!;
case JsonTokenType.StartArray:
return JsonSerializer.Deserialize<object[]>(ref reader, options)!;
return element.GetString();

case JsonValueKind.Number:
if (element.TryGetInt64(out long l))
{
return l;
}
return element.GetDouble();

case JsonValueKind.True:
return true;

case JsonValueKind.False:
return false;

case JsonValueKind.Null:
case JsonValueKind.Undefined:
return null;

default:
return JsonDocument.ParseValue(ref reader).RootElement.Clone();
throw new JsonException($"Unsupported JsonValueKind: {element.ValueKind}");
}
}

Expand Down
2 changes: 1 addition & 1 deletion templates/dotnet/Package/Exception.cs.twig
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ namespace {{spec.title | caseUcfirst}}
this.Type = type;
this.Response = response;
}

public {{spec.title | caseUcfirst}}Exception(string message, Exception inner)
: base(message, inner)
{
}
}
}

2 changes: 1 addition & 1 deletion templates/dotnet/Package/Extensions/Extensions.cs.twig
Original file line number Diff line number Diff line change
Expand Up @@ -624,4 +624,4 @@ namespace {{ spec.title | caseUcfirst }}.Extensions
return GetMimeTypeFromExtension(System.IO.Path.GetExtension(path));
}
}
}
}
4 changes: 2 additions & 2 deletions templates/dotnet/Package/Models/InputFile.cs.twig
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.IO;
using Appwrite.Extensions;
using {{ spec.title | caseUcfirst }}.Extensions;

namespace {{ spec.title | caseUcfirst }}.Models
{
Expand Down Expand Up @@ -38,4 +38,4 @@ namespace {{ spec.title | caseUcfirst }}.Models
SourceType = "bytes"
};
}
}
}
55 changes: 13 additions & 42 deletions templates/dotnet/Package/Models/Model.cs.twig
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@

{% set DefinitionClass = definition.name | caseUcfirst | overrideIdentifier %}
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
{% if definition.properties | filter(p => p.enum) | length > 0 %}
using {{ spec.title | caseUcfirst }}.Enums;
{% endif %}

namespace {{ spec.title | caseUcfirst }}.Models
{
public class {{ definition.name | caseUcfirst | overrideIdentifier }}
public class {{ DefinitionClass }}
{
{%~ for property in definition.properties %}
[JsonPropertyName("{{ property.name }}")]
public {{ sub_schema(property) | raw }} {{ property_name(definition, property) | overrideProperty(definition.name) }} { get; private set; }
public {{ sub_schema(property) }} {{ property_name(definition, property) | overrideProperty(definition.name) }} { get; private set; }

{%~ endfor %}
{%~ if definition.additionalProperties %}
public Dictionary<string, object> Data { get; private set; }

{%~ endif %}
public {{ definition.name | caseUcfirst | overrideIdentifier }}(
public {{ DefinitionClass }}(
{%~ for property in definition.properties %}
{{ sub_schema(property) | raw }} {{ property.name | caseCamel | escapeKeyword }}{% if not loop.last or (loop.last and definition.additionalProperties) %},{% endif %}
{{ sub_schema(property) }} {{ property.name | caseCamel | escapeKeyword }}{% if not loop.last or (loop.last and definition.additionalProperties) %},{% endif %}

{%~ endfor %}
{%~ if definition.additionalProperties %}
Expand All @@ -36,45 +38,14 @@ namespace {{ spec.title | caseUcfirst }}.Models
{%~ endif %}
}

public static {{ definition.name | caseUcfirst | overrideIdentifier }} From(Dictionary<string, object> map) => new {{ definition.name | caseUcfirst | overrideIdentifier }}(
public static {{ DefinitionClass }} From(Dictionary<string, object> map) => new {{ DefinitionClass }}(
{%~ for property in definition.properties %}
{%~ set v = 'v' ~ loop.index0 %}
{%~ set mapAccess = 'map["' ~ property.name ~ '"]' %}
{{ property.name | caseCamel | escapeKeyword | removeDollarSign }}:{{' '}}
{%- if property.sub_schema %}
{%- if property.type == 'array' -%}
map["{{ property.name }}"] is JsonElement jsonArray{{ loop.index }} ? jsonArray{{ loop.index }}.Deserialize<List<Dictionary<string, object>>>()!.Select(it => {{ property.sub_schema | caseUcfirst | overrideIdentifier }}.From(map: it)).ToList() : ((IEnumerable<Dictionary<string, object>>)map["{{ property.name }}"]).Select(it => {{ property.sub_schema | caseUcfirst | overrideIdentifier }}.From(map: it)).ToList()
{%- else -%}
{{ property.sub_schema | caseUcfirst | overrideIdentifier }}.From(map: map["{{ property.name }}"] is JsonElement jsonObj{{ loop.index }} ? jsonObj{{ loop.index }}.Deserialize<Dictionary<string, object>>()! : (Dictionary<string, object>)map["{{ property.name }}"])
{%- endif %}
{%- elseif property.enum %}
{%- set enumName = property['enumName'] ?? property.name -%}
{%- if not property.required -%}
map.TryGetValue("{{ property.name }}", out var enumRaw{{ loop.index }})
? enumRaw{{ loop.index }} == null
? null
: new {{ enumName | caseUcfirst }}(enumRaw{{ loop.index }}.ToString()!)
: null
{%- else -%}
new {{ enumName | caseUcfirst }}(map["{{ property.name }}"].ToString()!)
{%- endif %}
{%- else %}
{%- if property.type == 'array' -%}
map["{{ property.name }}"] is JsonElement jsonArrayProp{{ loop.index }} ? jsonArrayProp{{ loop.index }}.Deserialize<{{ property | typeName }}>()! : ({{ property | typeName }})map["{{ property.name }}"]
{%- else %}
{%- if property.type == "integer" or property.type == "number" %}
{%- if not property.required -%}map["{{ property.name }}"] == null ? null :{% endif %}Convert.To{% if property.type == "integer" %}Int64{% else %}Double{% endif %}(map["{{ property.name }}"])
{%- else %}
{%- if property.type == "boolean" -%}
({{ property | typeName }}{% if not property.required %}?{% endif %})map["{{ property.name }}"]
{%- else %}
{%- if not property.required -%}
map.TryGetValue("{{ property.name }}", out var {{ property.name | caseCamel | escapeKeyword | removeDollarSign }}) ? {{ property.name | caseCamel | escapeKeyword | removeDollarSign }}?.ToString() : null
{%- else -%}
map["{{ property.name }}"].ToString()
{%- endif %}
{%- endif %}
{%~ endif %}
{%~ endif %}
{%~ endif %}
{%- if not property.required -%}map.TryGetValue("{{ property.name }}", out var {{ v }}) ? {% endif -%}
{{ parse_value(property, mapAccess, v) }}
{%- if not property.required %} : null{% endif -%}
{%- if not loop.last or (loop.last and definition.additionalProperties) %},
{%~ endif %}
{%~ endfor %}
Expand Down
2 changes: 1 addition & 1 deletion templates/dotnet/Package/Models/UploadProgress.cs.twig
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ namespace {{ spec.title | caseUcfirst }}
ChunksUploaded = chunksUploaded;
}
}
}
}
2 changes: 1 addition & 1 deletion templates/dotnet/Package/Query.cs.twig
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,4 @@ namespace {{ spec.title | caseUcfirst }}
return new Query("notTouches", attribute, new List<object> { values }).ToString();
}
}
}
}
4 changes: 2 additions & 2 deletions templates/dotnet/Package/Role.cs.twig
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Appwrite
namespace {{ spec.title | caseUcfirst }}
{
/// <summary>
/// Helper class to generate role strings for Permission.
Expand Down Expand Up @@ -89,4 +89,4 @@ namespace Appwrite
return $"label:{name}";
}
}
}
}
1 change: 0 additions & 1 deletion templates/dotnet/Package/Services/ServiceTemplate.cs.twig
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{% import 'dotnet/base/utils.twig' as utils %}

using System;
using System.Collections.Generic;
using System.Linq;
Expand Down
Loading