Skip to content

Commit 29a759e

Browse files
more updates
1 parent 176443a commit 29a759e

File tree

5 files changed

+492
-102
lines changed

5 files changed

+492
-102
lines changed

Magic.IndexedDb/Helpers/ExpandoToTypeConverter.cs

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -40,50 +40,6 @@ private static void PrecomputePropertySetters(Type type)
4040
PropertySetters[prop.Name] = propertySetterExp.Compile();
4141
}
4242
}
43-
44-
public static T ConvertExpando(ExpandoObject expando)
45-
{
46-
Type type = typeof(T);
47-
48-
if (IsConcrete && HasParameterlessConstructor)
49-
{
50-
// Use the fastest method: Precomputed property setters
51-
var instance = Activator.CreateInstance<T>();
52-
var expandoDict = (IDictionary<string, object?>)expando;
53-
54-
foreach (var kvp in expandoDict)
55-
{
56-
if (PropertySetters.TryGetValue(kvp.Key, out var setter))
57-
{
58-
setter(instance, kvp.Value);
59-
}
60-
}
61-
62-
return instance;
63-
}
64-
else if (IsConcrete) // Concrete class without a parameterless constructor
65-
{
66-
var instance = Activator.CreateInstance(type);
67-
MagicSerializationHelper.PopulateObject(MagicSerializationHelper.SerializeObject(expando), instance);
68-
return (T)instance!;
69-
}
70-
else
71-
{
72-
// Last resort: If `T` is an interface or abstract class, fall back to full JSON deserialization
73-
var instance = MagicSerializationHelper.DeserializeObject<T>(MagicSerializationHelper.SerializeObject(expando))!;
74-
75-
// Check if we can cache this as a known type
76-
if (!NonConcreteTypeCache.ContainsKey(type))
77-
{
78-
NonConcreteTypeCache[type] = true;
79-
80-
// Dynamically compute property setters for this type
81-
PrecomputePropertySetters(type);
82-
}
83-
84-
return instance;
85-
}
86-
}
8743
}
8844

8945

Magic.IndexedDb/Helpers/PropertyMappingCache.cs

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Magic.IndexedDb.Models;
33
using Magic.IndexedDb.SchemaAnnotations;
44
using System;
5+
using System.Collections;
56
using System.Collections.Concurrent;
67
using System.Collections.Generic;
78
using System.Linq;
@@ -15,6 +16,104 @@ public static class PropertyMappingCache
1516
{
1617
internal static readonly ConcurrentDictionary<string, Dictionary<string, MagicPropertyEntry>> _propertyCache = new();
1718

19+
20+
public static Dictionary<string, MagicPropertyEntry> GetTypeOfTProperties(Type type)
21+
{
22+
EnsureTypeIsCached(type);
23+
if (_propertyCache.TryGetValue(type.FullName!, out var properties))
24+
{
25+
return properties;
26+
}
27+
throw new Exception("Something went very wrong getting GetTypeOfTProperties");
28+
}
29+
30+
public static bool IsSimpleType(Type type)
31+
{
32+
return type.IsPrimitive ||
33+
type.IsEnum ||
34+
type == typeof(string) ||
35+
type == typeof(decimal) ||
36+
type == typeof(DateTime) ||
37+
type == typeof(DateTimeOffset) ||
38+
type == typeof(Guid) ||
39+
type == typeof(Uri) ||
40+
type == typeof(TimeSpan);
41+
}
42+
43+
44+
public static IEnumerable<Type> GetAllNestedComplexTypes(IEnumerable<PropertyInfo> properties)
45+
{
46+
HashSet<Type> complexTypes = new();
47+
Stack<Type> typeStack = new();
48+
49+
// Initial population of the stack
50+
foreach (var property in properties)
51+
{
52+
if (IsComplexType(property.PropertyType))
53+
{
54+
typeStack.Push(property.PropertyType);
55+
complexTypes.Add(property.PropertyType);
56+
}
57+
}
58+
59+
// Process all nested complex types
60+
while (typeStack.Count > 0)
61+
{
62+
var currentType = typeStack.Pop();
63+
var nestedProperties = currentType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
64+
65+
foreach (var nestedProperty in nestedProperties)
66+
{
67+
if (IsComplexType(nestedProperty.PropertyType) && !complexTypes.Contains(nestedProperty.PropertyType))
68+
{
69+
complexTypes.Add(nestedProperty.PropertyType);
70+
typeStack.Push(nestedProperty.PropertyType);
71+
}
72+
}
73+
}
74+
75+
return complexTypes;
76+
}
77+
78+
/*public static bool IsComplexType(Type type)
79+
{
80+
return !(IsSimpleType(type)
81+
|| type == typeof(string)
82+
|| typeof(IEnumerable).IsAssignableFrom(type) // Non-generic IEnumerable
83+
|| (type.IsGenericType && typeof(IEnumerable<>).IsAssignableFrom(type.GetGenericTypeDefinition())) // Generic IEnumerable<T>
84+
|| type.IsArray); // Arrays are collections too
85+
}*/
86+
87+
public static bool IsComplexType(Type type)
88+
{
89+
if (IsSimpleType(type) || type == typeof(string))
90+
return false;
91+
92+
// Handle generic collections like List<T>, Dictionary<TKey, TValue>
93+
if (type.IsGenericType)
94+
{
95+
Type genericTypeDef = type.GetGenericTypeDefinition();
96+
97+
// If it's a generic IEnumerable<T>, get the type argument and check if it's complex
98+
if (typeof(IEnumerable<>).IsAssignableFrom(genericTypeDef))
99+
{
100+
Type itemType = type.GetGenericArguments()[0];
101+
return IsComplexType(itemType);
102+
}
103+
104+
// Otherwise, it might be a generic class like StoreRecord<T>
105+
return type.GetGenericArguments().Any(IsComplexType);
106+
}
107+
108+
// Handle non-generic collections like arrays
109+
if (typeof(IEnumerable).IsAssignableFrom(type) || type.IsArray)
110+
return false;
111+
112+
return true; // Consider anything else a complex object
113+
}
114+
115+
116+
18117
/// <summary>
19118
/// Gets the C# property name given a JavaScript property name.
20119
/// </summary>
@@ -160,8 +259,12 @@ internal static void EnsureTypeIsCached(Type type)
160259
// Initialize the dictionary for this type
161260
var propertyEntries = new Dictionary<string, MagicPropertyEntry>();
162261

262+
List<MagicPropertyEntry> newMagicPropertyEntry = new List<MagicPropertyEntry>();
163263
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
164264
{
265+
if (property.GetIndexParameters().Length > 0)
266+
continue; // 🔥 Skip indexers entirely
267+
165268
string propertyKey = property.Name; // Now stored as string, not PropertyInfo
166269

167270
var columnAttribute = property.GetCustomAttributes()
@@ -180,12 +283,21 @@ internal static void EnsureTypeIsCached(Type type)
180283
property.IsDefined(typeof(MagicPrimaryKeyAttribute), inherit: true),
181284
property.IsDefined(typeof(MagicNotMappedAttribute), inherit: true)
182285
);
183-
286+
newMagicPropertyEntry.Add(magicEntry);
184287
propertyEntries[propertyKey] = magicEntry; // Store property entry with string key
185288
}
186289

187290
// Cache the properties for this type
188291
_propertyCache[typeKey] = propertyEntries;
292+
293+
var complexTypes = GetAllNestedComplexTypes(newMagicPropertyEntry.Select(x => x.Property));
294+
if (complexTypes != null && complexTypes.Any())
295+
{
296+
foreach (var comp in complexTypes)
297+
{
298+
EnsureTypeIsCached(comp);
299+
}
300+
}
189301
}
190302
}
191303
}

Magic.IndexedDb/IndexDbManager.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Text.Json.Nodes;
1111
using Magic.IndexedDb.Interfaces;
1212
using static System.Runtime.InteropServices.JavaScript.JSType;
13+
using Microsoft.Extensions.Options;
1314

1415
namespace Magic.IndexedDb
1516
{
@@ -565,9 +566,19 @@ internal async Task CallJsAsync(string functionName, CancellationToken token, pa
565566

566567
internal async Task<T> CallJsAsync<T>(string functionName, CancellationToken token, params ITypedArgument[] args)
567568
{
569+
570+
var ss = typeof(T);
571+
568572
var settings = new MagicJsonSerializationSettings() { UseCamelCase = true };
569573
object[] serializedArgs = MagicSerializationHelper.SerializeObjects(args, settings);
570-
return await this._jsModule.InvokeAsync<T>(functionName, token, serializedArgs);
574+
// Invoke JavaScript function and retrieve result as a JsonElement to avoid type mismatches
575+
var resultJsonElement = await _jsModule.InvokeAsync<JsonElement>(functionName, token, serializedArgs);
576+
577+
// Convert JsonElement to a JSON string for custom deserialization
578+
string resultJson = resultJsonElement.GetRawText();
579+
580+
var result = MagicSerializationHelper.DeserializeObject<T>(resultJson, settings);
581+
return result;
571582
}
572583
}
573584
}

0 commit comments

Comments
 (0)