22using Magic . IndexedDb . Models ;
33using Magic . IndexedDb . SchemaAnnotations ;
44using System ;
5+ using System . Collections ;
56using System . Collections . Concurrent ;
67using System . Collections . Generic ;
78using 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}
0 commit comments