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

Improvements related to Remote MongoDB access #3414

Merged
merged 26 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8bdb772
Add a smoke test
nirinchev Aug 9, 2023
9f2b1d3
Wire up basic serialization through the generator
nirinchev Aug 9, 2023
8a84e66
wip
nirinchev Aug 31, 2023
ee1aaa3
Add more tests
nirinchev Sep 4, 2023
dc52531
Add tests for links
nirinchev Sep 25, 2023
29ecbad
Merge branch 'main' into ni/remote-mongo-improvements
nirinchev Oct 10, 2023
73aac17
Embedded object changes
nirinchev Nov 1, 2023
26f0381
Merge branch 'main' into ni/remote-mongo-improvements
nirinchev Nov 22, 2023
fb501b8
Resolve some warnings
nirinchev Nov 22, 2023
80ca2f2
Add wasm workload
nirinchev Nov 23, 2023
3d81935
Setup workloads everywhere
nirinchev Nov 23, 2023
a416e5c
Try to setup .net 6
nirinchev Nov 24, 2023
708f467
Setup .net before we install the workloads
nirinchev Nov 24, 2023
afa6159
Add global.json
nirinchev Nov 24, 2023
00c6e67
Remove wasm-tools-net6
nirinchev Nov 24, 2023
577715a
Merge branch 'main' into ni/remote-mongo-improvements
papafe Jan 2, 2024
324d69c
Static queries build on (#3487)
papafe Jan 10, 2024
5dc4e5d
Small fix
papafe Jan 10, 2024
38be2f5
Added tests to explain datetime differences
papafe Jan 10, 2024
b8048fb
Added support for legacy serialization
papafe Jan 10, 2024
ecff1d1
Avoiding sub-millisecond precision in date generation
papafe Jan 11, 2024
5892f02
Small corrections
papafe Jan 11, 2024
2250e8d
Added wait for tests
papafe Jan 11, 2024
65d7895
Error corrected
papafe Jan 23, 2024
94496cc
Removed comment
papafe Jan 24, 2024
1f60b9b
Merge branch 'main' into ni/remote-mongo-improvements
papafe Feb 6, 2024
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
1 change: 1 addition & 0 deletions .github/templates/build-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ jobs:
steps:
- #@ template.replace(checkoutCode())
- #@ template.replace(setupAndroid())
- _: #@ template.replace(setupDotnet("6.0.417"))
- #@ setupWorkloads('tvos ios maccatalyst android')
- name: Set version suffix
id: set-version-suffix
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/build-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ jobs:
uses: android-actions/setup-android@7c5672355aaa8fde5f97a91aa9a99616d1ace6bc
- name: Install SDK platform 21
run: sdkmanager --install "platforms;android-21"
- name: Configure .NET
uses: actions/setup-dotnet@607fce577a46308457984d59e4954e075820f10a
with:
dotnet-version: 6.0.417
- name: Setup workloads
run: dotnet workload install tvos ios maccatalyst android
- name: Set version suffix
Expand Down Expand Up @@ -210,11 +214,11 @@ jobs:
uses: nirinchev/cache@29e8e4dd9148ea81f9e188480132072cb6cc92d8
with:
path: C:\docfx
key: docfx-2.62.1
key: docfx-2.70.4
- name: Download docfx
if: inputs.build-docs && steps.check-docfx-cache.outputs.cache-hit != 'true'
run: |
Invoke-WebRequest -Uri https://github.com/dotnet/docfx/releases/download/v2.62.1/docfx-win-x64-v2.62.1.zip -OutFile C:\docfx.zip
Invoke-WebRequest -Uri https://github.com/dotnet/docfx/releases/download/v2.70.4/docfx-win-x64-v2.70.4.zip -OutFile C:\docfx.zip
Expand-Archive -Path C:\docfx.zip -DestinationPath C:\docfx
shell: powershell
- name: Configure .NET
Expand Down
5 changes: 5 additions & 0 deletions Realm.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=animales/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=asyncopentask/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=autoimplemented/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=autoverify/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=baasapikey/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=baascluster/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=baasdifferentiator/@EntryIndexedValue">True</s:Boolean>
Expand Down Expand Up @@ -58,6 +59,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Name_0020/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=nomoreuserthread/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=notificationtoken/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Noupsert/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=nulled/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=N_00FAmenor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=paramref/@EntryIndexedValue">True</s:Boolean>
Expand All @@ -66,6 +68,8 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Quenta/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Quenya/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Queryables/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=realmlogfile/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=realmloglevel/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=refcounted/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=refcounting/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Reflectable/@EntryIndexedValue">True</s:Boolean>
Expand All @@ -92,6 +96,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=syncsession/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=syncuser/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=tablekey/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=testhost/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=t_0020rec/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unbindlist/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unbindlistlock/@EntryIndexedValue">True</s:Boolean>
Expand Down
2 changes: 1 addition & 1 deletion Realm/Realm.Fody/Realm.Fody.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</PropertyGroup>
<ItemGroup Label="References">
<PackageReference Include="FodyHelpers" Version="6.*" PrivateAssets="All" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.1">
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
6 changes: 3 additions & 3 deletions Realm/Realm.PlatformHelpers/Realm.PlatformHelpers.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

<TargetFrameworks>netstandard2.0</TargetFrameworks>
<!-- Mono MSBuild (16.0) on macOS cannot target .NET 6 so we can only add the .NET 6 tfms for dotnet build/Windows MSBuild -->
<TargetFrameworks Condition="$([MSBuild]::IsOsPlatform('Windows')) OR (!$([MSBuild]::IsOsPlatform('Linux')) AND '$(MSBuildVersion)' &gt;= '17.0')">
<TargetFrameworks Condition="($([System.OperatingSystem]::IsWindows()) AND '$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'X64') OR ($([System.OperatingSystem]::IsMacOS()) AND '$(MSBuildVersion)' &gt;= '17.0')">
$(TargetFrameworks);net6.0-ios;net6.0-android;net6.0-maccatalyst;net6.0-tvos
</TargetFrameworks>
<!-- dotnet build on macOS cannot target Xamarin.XYZ -->
<!-- Additionally, the Xamarin targets are not available on Arm64 Windows -->
<TargetFrameworks Condition="($([MSBuild]::IsOsPlatform('Windows')) AND '$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'X64') OR (!$([MSBuild]::IsOsPlatform('Linux')) AND '$(MSBuildVersion)' &lt; '17.0')">
<TargetFrameworks Condition="($([System.OperatingSystem]::IsWindows()) AND '$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'X64') OR ($([System.OperatingSystem]::IsMacOS()) AND '$(MSBuildVersion)' &lt; '17.0')">
$(TargetFrameworks);MonoAndroid5;Xamarin.iOS10;Xamarin.TVOS10;Xamarin.Mac20
</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOsPlatform('Windows'))">$(TargetFrameworks);uap10.0.19041;</TargetFrameworks>
<TargetFrameworks Condition="$([System.OperatingSystem]::IsWindows())">$(TargetFrameworks);uap10.0.19041;</TargetFrameworks>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<LangVersion>9.0</LangVersion>
<nullable>enable</nullable>
Expand Down
146 changes: 128 additions & 18 deletions Realm/Realm.SourceGenerator/ClassCodeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand All @@ -29,6 +30,7 @@ internal class ClassCodeBuilder
{
private readonly string[] _defaultNamespaces =
{
"MongoDB.Bson.Serialization",
"System",
"System.Collections.Generic",
"System.Linq",
Expand All @@ -49,6 +51,7 @@ internal class ClassCodeBuilder
private readonly string _accessorInterfaceName;
private readonly string _managedAccessorClassName;
private readonly string _unmanagedAccessorClassName;
private readonly string _serializerClassName;

public ClassCodeBuilder(ClassInfo classInfo, GeneratorConfig generatorConfig)
{
Expand All @@ -72,18 +75,14 @@ public ClassCodeBuilder(ClassInfo classInfo, GeneratorConfig generatorConfig)
_accessorInterfaceName = $"I{className}Accessor";
_managedAccessorClassName = $"{className}ManagedAccessor";
_unmanagedAccessorClassName = $"{className}UnmanagedAccessor";
_serializerClassName = $"{className}Serializer";
}

public string GenerateSource()
{
var usings = GetUsings();

var interfaceString = GenerateInterface().Indent();
var managedAccessorString = GenerateManagedAccessor().Indent();
var unmanagedAccessorString = GenerateUnmanagedAccessor().Indent();
var classObjectHelperString = GenerateClassObjectHelper().Indent();

var partialClassString = GeneratePartialClass(interfaceString, managedAccessorString, unmanagedAccessorString, classObjectHelperString);
var partialClassString = GeneratePartialClass();

return $@"// <auto-generated />
#nullable enable
Expand Down Expand Up @@ -129,7 +128,7 @@ internal interface {_accessorInterfaceName} : Realms.IRealmAccessor
}}";
}

private string GeneratePartialClass(string interfaceString, string managedAccessorString, string unmanagedAccessorString, string classObjectHelperString)
private string GeneratePartialClass()
{
var schemaProperties = new StringBuilder();
var copyToRealm = new StringBuilder();
Expand Down Expand Up @@ -496,15 +495,24 @@ public override bool Equals(object? obj)
[Woven(typeof({_helperClassName})), Realms.Preserve(AllMembers = true)]
{SyntaxFacts.GetText(_classInfo.Accessibility)} partial class {_classInfo.Name} : {baseInterface}, INotifyPropertyChanged, IReflectableType
{{

[Realms.Preserve]
static {_classInfo.Name}()
{{
Realms.Serialization.RealmObjectSerializer.Register(new {_serializerClassName}());
}}

{contents.Indent()}

{classObjectHelperString}
{GenerateClassObjectHelper().Indent()}

{GenerateInterface().Indent()}

{interfaceString}
{GenerateManagedAccessor().Indent()}

{managedAccessorString}
{GenerateUnmanagedAccessor().Indent()}

{unmanagedAccessorString}
{GenerateSerializer().Indent()}
}}";

foreach (var enclosingClass in _classInfo.EnclosingClasses)
Expand Down Expand Up @@ -583,23 +591,21 @@ private string GenerateUnmanagedAccessor()
}
else
{
var propertyMapToName = property.GetMappedOrOriginalName();

string constructorString;

switch (property.TypeInfo.CollectionType)
{
case CollectionType.List:
constructorString = $"new List<{internalType}>()";
getListValueLines.AppendLine($@"""{propertyMapToName}"" => (IList<T>){property.Name},");
getListValueLines.AppendLine($@"""{stringName}"" => (IList<T>){property.Name},");
break;
case CollectionType.Set:
constructorString = $"new HashSet<{internalType}>(RealmSet<{internalType}>.Comparer)";
getSetValueLines.AppendLine($@"""{propertyMapToName}"" => (ISet<T>){property.Name},");
getSetValueLines.AppendLine($@"""{stringName}"" => (ISet<T>){property.Name},");
break;
case CollectionType.Dictionary:
constructorString = $"new Dictionary<string, {internalType}>()";
getDictionaryValueLines.AppendLine($@"""{propertyMapToName}"" => (IDictionary<string, TValue>){property.Name},");
getDictionaryValueLines.AppendLine($@"""{stringName}"" => (IDictionary<string, TValue>){property.Name},");
break;
default:
throw new NotImplementedException($"Collection {property.TypeInfo.CollectionType} is not supported yet");
Expand Down Expand Up @@ -756,7 +762,7 @@ private string GenerateUnmanagedAccessor()
}

return $@"[EditorBrowsable(EditorBrowsableState.Never), Realms.Preserve(AllMembers = true)]
internal class {_unmanagedAccessorClassName} : Realms.UnmanagedAccessor, {_accessorInterfaceName}
private class {_unmanagedAccessorClassName} : Realms.UnmanagedAccessor, {_accessorInterfaceName}
{{
public override ObjectSchema ObjectSchema => {_classInfo.Name}.RealmSchema;

Expand Down Expand Up @@ -865,12 +871,116 @@ private string GenerateManagedAccessor()
}

return $@"[EditorBrowsable(EditorBrowsableState.Never), Realms.Preserve(AllMembers = true)]
internal class {_managedAccessorClassName} : Realms.ManagedAccessor, {_accessorInterfaceName}
private class {_managedAccessorClassName} : Realms.ManagedAccessor, {_accessorInterfaceName}
{{
{propertiesBuilder.Indent(trimNewLines: true)}
}}";
}

private string GenerateSerializer()
{
var serializeValueLines = new StringBuilder();
var readValueLines = new StringBuilder();
var readArrayElementLines = new StringBuilder();
var readDocumentFieldLines = new StringBuilder();

foreach (var property in _classInfo.Properties)
{
var name = property.Name;
var stringName = property.GetMappedOrOriginalName();

if (property.TypeInfo.IsBacklink)
{
continue; // Backlinks are not de/serialized
}
else if (property.TypeInfo.IsCollection)
{
serializeValueLines.AppendLine($"Write{property.TypeInfo.CollectionType}(context, args, \"{stringName}\", value.{name});");
if (property.TypeInfo.IsDictionary)
{
var type = property.TypeInfo.GetCorrectlyAnnotatedTypeName(property.IsRequired).InternalType;

var deserialize = property.TypeInfo.InternalType!.ObjectType is ObjectType.None or ObjectType.EmbeddedObject
? $"BsonSerializer.LookupSerializer<{type}>().Deserialize(context)"
: $"LookupSerializer<{type}>()!.DeserializeById(context)!";

readDocumentFieldLines.AppendLine($@"case ""{stringName}"":
instance.{name}[fieldName] = {deserialize};
break;");
}
else
{
var type = property.TypeInfo.GetCorrectlyAnnotatedTypeName(property.IsRequired).InternalType;

var deserialize = property.TypeInfo.InternalType!.ObjectType is ObjectType.None or ObjectType.EmbeddedObject
? $"BsonSerializer.LookupSerializer<{type}>().Deserialize(context)"
: $"LookupSerializer<{type}>()!.DeserializeById(context)!";

readArrayElementLines.AppendLine($@"case ""{stringName}"":
instance.{name}.Add({deserialize});
break;");
}
}
else
{
var type = property.TypeInfo.GetCorrectlyAnnotatedTypeName(property.IsRequired).CompleteType;

serializeValueLines.AppendLine($"WriteValue(context, args, \"{stringName}\", value.{name});");
var deserialize = property.TypeInfo.ObjectType is ObjectType.None or ObjectType.EmbeddedObject
? $"BsonSerializer.LookupSerializer<{type}>().Deserialize(context)"
: $"LookupSerializer<{type}>()!.DeserializeById(context)";
readValueLines.AppendLine($@"case ""{stringName}"":
instance.{name} = {deserialize};
break;");
}
}

return $@"[EditorBrowsable(EditorBrowsableState.Never), Realms.Preserve(AllMembers = true)]
private class {_serializerClassName} : Realms.Serialization.RealmObjectSerializer<{_classInfo.Name}>
{{
protected override void SerializeValue(MongoDB.Bson.Serialization.BsonSerializationContext context, BsonSerializationArgs args, {_classInfo.Name} value)
{{
context.Writer.WriteStartDocument();

{serializeValueLines.Indent(2, trimNewLines: true)}

context.Writer.WriteEndDocument();
}}

protected override {_classInfo.Name} CreateInstance() => new {_classInfo.Name}();

protected override void ReadValue({_classInfo.Name} instance, string name, BsonDeserializationContext context)
{{
{(readValueLines.Length == 0
? "// No Realm properties to deserialize"
: $@"switch (name)
{{
{readValueLines.Indent(trimNewLines: true)}
}}").Indent(2)}
}}

protected override void ReadArrayElement({_classInfo.Name} instance, string name, BsonDeserializationContext context)
{{
{(readArrayElementLines.Length == 0
? "// No persisted list/set properties to deserialize"
: $@"switch (name)
{{
{readArrayElementLines.Indent(trimNewLines: true)}
}}").Indent(2)}
}}

protected override void ReadDocumentField({_classInfo.Name} instance, string name, string fieldName, BsonDeserializationContext context)
{{
{(readDocumentFieldLines.Length == 0
? "// No persisted dictionary properties to deserialize"
: $@"switch (name)
{{
{readDocumentFieldLines.Indent(trimNewLines: true)}
}}").Indent(2)}
}}
}}";
}

private static string GetBackingFieldName(string propertyName)
{
return "_" + char.ToLowerInvariant(propertyName[0]) + propertyName[1..];
Expand Down
4 changes: 2 additions & 2 deletions Realm/Realm.SourceGenerator/Realm.SourceGenerator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<RootNamespace>Realms.SourceGenerator</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.1">
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down Expand Up @@ -57,7 +57,7 @@
</ItemGroup>
</Target>
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" GeneratePathProperty="true" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion Realm/Realm.UnityUtils/Realm.UnityUtils.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.1">
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
2 changes: 1 addition & 1 deletion Realm/Realm.UnityWeaver/Realm.UnityWeaver.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.1">
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Loading
Loading