Skip to content

Commit

Permalink
versioning a point appears to work.... :D
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian Hawley committed Jul 7, 2024
1 parent 5d9a402 commit ca18da0
Show file tree
Hide file tree
Showing 12 changed files with 60 additions and 31 deletions.
1 change: 1 addition & 0 deletions src/Speckle.Core/Reflection/ITypeFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ namespace Speckle.Core.Reflection;
public interface ITypeFinder
{
IList<Type> GetTypesWhereSubclassOf(IEnumerable<Assembly> assemblies, Type subclassOf);
IList<Type> GetTypesWhereImplementing(IEnumerable<Assembly> assemblies, Type subclassOf);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public SingletonTypeInstanceResolver(ITypeFinder typeFinder)

// POC: not wild about evaluating this during construction but... is that still a thing?
// could be done on the fly... it will require some locking semantics if used during deserialisation
var foundTypes = _typeFinder.GetTypesWhereSubclassOf(AppDomain.CurrentDomain.GetAssemblies(), typeof(TType));
var foundTypes = _typeFinder.GetTypesWhereImplementing(AppDomain.CurrentDomain.GetAssemblies(), typeof(TType));

// let's make an instance of each of these
// could also be done on the fly
Expand Down
26 changes: 24 additions & 2 deletions src/Speckle.Core/Reflection/TypeFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,31 @@ public IList<Type> GetTypesWhereSubclassOf(IEnumerable<Assembly> assemblies, Typ
{
types.AddRange(assembly.GetTypes().Where(x => x.IsSubclassOf(subclassOf) && !x.IsAbstract));
}
catch (TypeLoadException)
// POC: right one? more?
catch (ReflectionTypeLoadException)
{
// POC: guard against loading things that cause explosions
// POC: guard against loading things that cause explosions due to not being able to load assemblies but are not real issues
}
}

return types;
}

public IList<Type> GetTypesWhereImplementing(IEnumerable<Assembly> assemblies, Type subclassOf)
{
List<Type> types = new();

// this assumes the DUI2 objects are not already loaded
foreach (var assembly in assemblies)
{
try
{
types.AddRange(assembly.GetTypes().Where(x => x.GetInterfaces().Contains(subclassOf) && !x.IsAbstract));
}
// POC: right one? more?
catch (ReflectionTypeLoadException)
{
// POC: guard against loading things that cause explosions due to not being able to load assemblies but are not real issues
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ namespace Speckle.Core.SchemaVersioning;
public interface ISchemaObjectUpgradeManager<TInputType, TOutputType>
where TInputType : class where TOutputType : class
{
TOutputType UpgradeObject(TInputType input, string typeName, Version inputVersion, Version schemaVersion);
TOutputType UpgradeObject(TInputType input, string typeName, Version inputSchemaVersion, Version loadedSchemaVersion);
}
11 changes: 5 additions & 6 deletions src/Speckle.Core/SchemaVersioning/SchemaObjectUpgradeManager.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Reflection;
using Speckle.Core.Logging;
using Speckle.Core.Models;
using Speckle.Core.Reflection;

namespace Speckle.Core.SchemaVersioning;
Expand All @@ -17,24 +15,25 @@ public SchemaObjectUpgradeManager(ITypeInstanceResolver<ISchemaObjectUpgrader<TI
_typeInstanceResolver = typeInstanceResolver;
}

public TOutputType UpgradeObject(TInputType input, string typeName, Version inputVersion, Version schemaVersion)
public TOutputType UpgradeObject(TInputType input, string typeName, Version inputSchemaVersion, Version loadedSchemaVersion)
{
TOutputType? upgraded = null;

// we try and upgrade while-ever the versions don't match
while (inputVersion < schemaVersion)
while (inputSchemaVersion < loadedSchemaVersion)
{
// building this must be done consistently
string typeKey = NamedTypeAttribute.CreateTypeNameWithKeySuffix(typeName, inputVersion.ToString());
string typeKey = NamedTypeAttribute.CreateTypeNameWithKeySuffix(typeName, inputSchemaVersion.ToString());

// POC: do we expect there must always be types?
if (!_typeInstanceResolver.TryResolve(typeKey, out ISchemaObjectUpgrader<TInputType, TOutputType> upgrader))
{
// there's no upgrader for this
break;
}

upgraded = upgrader.Upgrade(input);
inputVersion = upgrader.UpgradeTo;
inputSchemaVersion = upgrader.UpgradeTo;
}

// if we didn't do any upgrading, then we should be pass the input directly to the output
Expand Down
30 changes: 18 additions & 12 deletions src/Speckle.Core/Serialisation/BaseObjectDeserializerV2.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Speckle.Core.Common;
using Speckle.Core.Kits;
using Speckle.Core.Logging;
using Speckle.Core.Models;
using Speckle.Core.SchemaVersioning;
Expand Down Expand Up @@ -355,17 +349,17 @@ private Base Dict2Base(Dictionary<string, object?> dictObj)
string typeName = (string) dictObj[SerializationConstants.TYPE_DISCRIMINATOR]!;

// here we're getting the actual type to deserialise into, this won't be the type we return
// POC: is there any guarantee this can't happen? probably not ATM
// it's almost certainly a bug if the type returned is a version and not the latest!
(Version objectVersion, CachedTypeInfo cachedTypeInfo) = _typeCache.GetMatchedTypeOrLater(typeName, _payloadSchemaVersion);

Base baseObj = (Base) Activator.CreateInstance(cachedTypeInfo.Type);

dictObj.Remove(SerializationConstants.TYPE_DISCRIMINATOR);
dictObj.Remove(SerializationConstants.CLOSURE_PROPERTY_NAME);

var props = cachedTypeInfo.Props;

var onDeserializedCallbacks = cachedTypeInfo.Callbacks;

dictObj.Remove(SerializationConstants.TYPE_DISCRIMINATOR);
dictObj.Remove(SerializationConstants.CLOSURE_PROPERTY_NAME);

foreach (var entry in dictObj)
{
string lowerPropertyName = entry.Key.ToLower();
Expand Down Expand Up @@ -407,9 +401,20 @@ private Base Dict2Base(Dictionary<string, object?> dictObj)
{
bb.filePath = bb.GetLocalDestinationPath(BlobStorageFolder);
}


// if (cachedTypeInfo.Type.FullName.NotNull().ToLower().Contains("point"))
// {
// Debug.WriteLine("breakpoint :p");
// }

// version the object
baseObj = _objectUpgradeManager.UpgradeObject(baseObj, cachedTypeInfo.Type.FullName.NotNull(), objectVersion, _payloadSchemaVersion);
// POC: we need to cache the right name here, because reflecting to get the mame is meh
baseObj = _objectUpgradeManager.UpgradeObject(
baseObj,
cachedTypeInfo.Type.FullName.NotNull(),
_payloadSchemaVersion,
_typeCache.LoadedSchemaVersion);

// POC: what are these callback methods? are they used?
// Do they need calling on the object BEFORE upgrading it? Do they need calling AGAIN after upgrading it?
Expand All @@ -418,6 +423,7 @@ private Base Dict2Base(Dictionary<string, object?> dictObj)
onDeserialized.Invoke(baseObj, new object?[] { null });
}

// POC: we need to be returning the latest version
return baseObj;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ public void EnsureCacheIsBuilt()

CacheType(typeName, version, typeCacheInfo);
}
catch (TypeLoadException)
// POC: right one? more?
catch (ReflectionTypeLoadException)
{
// POC: guard against loading things that cause explosions
}
Expand Down
2 changes: 1 addition & 1 deletion src/Speckle.Core/SpeckleObjectSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ namespace Speckle.Core;
public class SpeckleObjectSchema
{
// POC: I'm not sure about using the Version object ATM, strings may be just as a straight-forward...
public static readonly Version Version = new Version(3, 0, 0);
public static readonly Version Version = new Version(0, 2, 0);
}
2 changes: 1 addition & 1 deletion src/Speckle.Objects/Speckle.Objects.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
</ItemGroup>

<ItemGroup>
<Folder Include="Versions\V_0_1_0\BuiltElements\" />
<Folder Include="Versions\V_0_0_0\" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion src/Speckle.Objects/SpeckleSchemaInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

public static class SpeckleSchemaInfo
{
public static readonly Version Version = new(0, 2, 0);
public static readonly Version Version = new(0, 1, 0);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using Speckle.Core.Models;
using Speckle.Newtonsoft.Json;

namespace Objects.Versions.V_0_1_0.Geometry;
namespace Objects.Versions.V_0_0_0.Geometry;

/// <summary>
/// A 3-dimensional point
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
using Speckle.Core.Reflection;
using Speckle.Core.SchemaVersioning;

using Source = Objects.Versions.V_0_1_0.Geometry.Point;
using Source = Objects.Versions.V_0_0_0.Geometry.Point;
using Destination = Objects.Geometry.Point;

namespace Speckle.Objects.Versions.V_0_1_0.Upgraders;
namespace Speckle.Objects.Versions.V_0_0_0.Upgraders;

// POC: consider weakness of strings here
// the type passed in is a bit janky, if we want to move from say RevitWall to Wall,
// then we would need to have some care about where the type name came from, as in this example
// POC: the version could come from some constant tbh and then it won't be wrong...
// is the typename off the source or destination :pained face:
[NamedType(typeof(Source), "0.1.0")]
[NamedType(typeof(Source), "0.0.0")]
public sealed class PointUpgrader : AbstractSchemaObjectBaseUpgrader<Source, Destination>
{
public PointUpgrader() : base(new Version(0,1,0), new Version(0,2, 0))
public PointUpgrader() : base(new Version(0,0,0), new Version(0,1, 0))
{

}
Expand Down

0 comments on commit ca18da0

Please sign in to comment.