Skip to content

Commit 72ff7fc

Browse files
We build once again
1 parent abb15d2 commit 72ff7fc

File tree

15 files changed

+220
-130
lines changed

15 files changed

+220
-130
lines changed

E2eTestWebApp/TestPages/OpenTestPage.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,15 @@ public async Task<string> StoreSchema()
5353
[
5454
new StoreSchema()
5555
{
56-
Name = "S1",
56+
TableName = "S1",
5757
Indexes = ["I11", "I12"],
5858
PrimaryKey = "P11",
5959
PrimaryKeyAuto = true,
6060
UniqueIndexes = ["U11", "U12"]
6161
},
6262
new StoreSchema()
6363
{
64-
Name = "S2",
64+
TableName = "S2",
6565
Indexes = [],
6666
PrimaryKey = "P21",
6767
PrimaryKeyAuto = false,

Magic.IndexedDb/Extensions/MagicCompoundExtension.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@
77

88
namespace Magic.IndexedDb
99
{
10-
public static class MagicCompoundExtension
10+
internal static class MagicCompoundExtension
1111
{
12-
public static IMagicCompoundIndex Create<T>(params Expression<Func<T, object>>[] keySelectors)
12+
public static IMagicCompoundIndex CreateIndex<T>(params Expression<Func<T, object>>[] keySelectors)
1313
{
1414
return InternalMagicCompoundIndex<T>.Create(keySelectors);
1515
}
16+
17+
public static IMagicCompoundKey CreateKey<T>(params Expression<Func<T, object>>[] keySelectors)
18+
{
19+
return InternalMagicCompoundKey<T>.Create(keySelectors);
20+
}
1621
}
1722
}

Magic.IndexedDb/Extensions/MagicTableTools.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,14 @@ namespace Magic.IndexedDb
1010
{
1111
public class MagicTableTool<T> where T : class, IMagicTableBase, new()
1212
{
13-
protected CreateCompoundIndex CreateCompoundIndex(params Expression<Func<T, object>>[] keySelectors)
13+
protected IMagicCompoundIndex CreateCompoundIndex(params Expression<Func<T, object>>[] keySelectors)
1414
{
15-
return MagicCompoundExtension.Create<T>(keySelectors);
15+
return MagicCompoundExtension.CreateIndex<T>(keySelectors);
16+
}
17+
18+
protected IMagicCompoundKey CreateCompoundKey(params Expression<Func<T, object>>[] keySelectors)
19+
{
20+
return MagicCompoundExtension.CreateKey<T>(keySelectors);
1621
}
1722
}
1823

Magic.IndexedDb/Factories/MagicDbFactory.cs

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,6 @@ public async Task<QuotaUsage> GetStorageEstimateAsync(CancellationToken cancella
115115
public async ValueTask<IMagicQuery<T>> Query<T>(IndexedDbSet indexedDbSet)
116116
where T : class, IMagicTableBase, new()
117117
{
118-
ValidateMagicTable<T>();
119-
120118
// Get database name and schema name
121119
string databaseName = indexedDbSet.DatabaseName;
122120
string schemaName = SchemaHelper.GetTableName<T>();
@@ -129,8 +127,6 @@ public async ValueTask<IMagicQuery<T>> Query<T>(
129127
Func<T, IndexedDbSet> dbSetSelector)
130128
where T : class, IMagicTableBase, new()
131129
{
132-
ValidateMagicTable<T>();
133-
134130
// Create an instance of T to access `DbSets`
135131
var modelInstance = new T();
136132

@@ -150,8 +146,6 @@ public async ValueTask<IMagicQuery<T>> Query<T>(
150146
public async ValueTask<IMagicQuery<T>> Query<T>()
151147
where T : class, IMagicTableBase, new()
152148
{
153-
ValidateMagicTable<T>();
154-
155149
string databaseName = SchemaHelper.GetDefaultDatabaseName<T>();
156150
string schemaName = SchemaHelper.GetTableName<T>();
157151
return await QueryOverride<T>(databaseName, schemaName);
@@ -160,26 +154,11 @@ public async ValueTask<IMagicQuery<T>> Query<T>()
160154
public async ValueTask<IMagicQuery<T>> QueryOverride<T>(string databaseNameOverride, string schemaNameOverride)
161155
where T: class, IMagicTableBase, new ()
162156
{
163-
var dbManager = await GetOrCreateDatabaseAsync(databaseName); // Ensure database is open
157+
var dbManager = await GetOrCreateDatabaseAsync(databaseNameOverride); // Ensure database is open
164158
return dbManager.Query<T>(databaseNameOverride, schemaNameOverride);
165159
}
166160

167161
private static readonly ConcurrentDictionary<Type, bool> _validatedTypes = new();
168162

169-
private static void ValidateMagicTable<T>()
170-
{
171-
Type type = typeof(T);
172-
173-
if (!_validatedTypes.TryGetValue(type, out bool isValid))
174-
{
175-
isValid = type.GetCustomAttribute<MagicTableAttribute>() != null;
176-
_validatedTypes[type] = isValid; // Cache the result
177-
178-
if (!isValid)
179-
{
180-
throw new InvalidOperationException($"The type '{type.Name}' is not a valid MagicTable class. Ensure it has the [MagicTableAttribute] applied.");
181-
}
182-
}
183-
}
184163
}
185164
}

Magic.IndexedDb/Helpers/MagicValidator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ public static void ValidateTables()
1616
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
1717
var magicTableClasses = assemblies
1818
.SelectMany(a => a.GetTypes())
19-
.Where(t => t.GetCustomAttribute<MagicTableAttribute>() != null)
19+
.Where(SchemaHelper.HasMagicTableInterface) // Uses the helper method
2020
.ToList();
2121

22+
2223
foreach (var type in magicTableClasses)
2324
{
2425
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

Magic.IndexedDb/Helpers/PropertyMappingCache.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,15 @@ public SearchPropEntry(Type type, Dictionary<string, MagicPropertyEntry> _proper
2727
jsNameToCsName[entry.Value.JsPropertyName] = entry.Value.CsharpPropertyName;
2828
}
2929

30-
// Extract MagicTableAttribute info
31-
var magicTableAttr = type.GetCustomAttribute<MagicTableAttribute>();
32-
if (magicTableAttr != null && !string.IsNullOrWhiteSpace(magicTableAttr.SchemaName))
30+
// Extract IMagicTableBase info
31+
if (typeof(IMagicTableBase).IsAssignableFrom(type))
3332
{
34-
EffectiveTableName = magicTableAttr.SchemaName; // Use the schema name
35-
EnforcePascalCase = true; // Prevent camel casing
33+
var instance = Activator.CreateInstance(type) as IMagicTableBase;
34+
if (instance != null)
35+
{
36+
EffectiveTableName = instance.GetTableName(); // Use the provided table name
37+
EnforcePascalCase = true; // Prevent camel casing
38+
}
3639
}
3740
else
3841
{
@@ -495,7 +498,7 @@ internal static void EnsureTypeIsCached(Type type)
495498
// Initialize the dictionary for this type
496499
var propertyEntries = new Dictionary<string, MagicPropertyEntry>(StringComparer.OrdinalIgnoreCase);
497500

498-
bool hasMagicTableAttribute = type.IsDefined(typeof(MagicTableAttribute), inherit: true);
501+
bool isMagicTable = SchemaHelper.HasMagicTableInterface(type);
499502

500503
List<MagicPropertyEntry> newMagicPropertyEntry = new List<MagicPropertyEntry>();
501504
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy))
@@ -520,9 +523,8 @@ internal static void EnsureTypeIsCached(Type type)
520523
property.IsDefined(typeof(MagicUniqueIndexAttribute), inherit: true),
521524
property.IsDefined(typeof(MagicPrimaryKeyAttribute), inherit: true),
522525
property.IsDefined(typeof(MagicNotMappedAttribute), inherit: true),
523-
hasMagicTableAttribute
526+
isMagicTable
524527
|| property.IsDefined(typeof(MagicNameAttribute), inherit: true)
525-
|| property.IsDefined(typeof(MagicTableAttribute), inherit: true)
526528
);
527529

528530
newMagicPropertyEntry.Add(magicEntry);

Magic.IndexedDb/Helpers/SchemaHelper.cs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ public static class SchemaHelper
1515
//private static readonly ConcurrentDictionary<string, List<StoreSchema>> _databaseSchemasCache = new();
1616
//private static bool _schemasScanned = false;
1717
//private static readonly object _lock = new();
18+
internal static readonly ConcurrentDictionary<string, Type> _schemaCache = new();
19+
20+
internal static void EnsureSchemaIsCached(Type type)
21+
{
22+
string typeKey = type.FullName!;
23+
24+
_schemaCache.GetOrAdd(typeKey, _ =>
25+
{
26+
if (!typeof(IMagicTableBase).IsAssignableFrom(type))
27+
throw new InvalidOperationException($"Type {type.Name} does not implement IMagicTableBase.");
28+
29+
return type; // Cache the type itself
30+
});
31+
}
1832

1933
private static readonly ConcurrentDictionary<Type, string> _tableNameCache = new();
2034
private static readonly ConcurrentDictionary<Type, string> _databaseNameCache = new();
@@ -36,7 +50,7 @@ public static class SchemaHelper
3650
return databaseName;
3751
}
3852

39-
public static string GetTableName<T>() where T : IMagicTableBase, new()
53+
public static string GetTableName<T>() where T : class
4054
{
4155
Type type = typeof(T);
4256

@@ -45,18 +59,38 @@ public static class SchemaHelper
4559
return cachedTableName;
4660
}
4761

48-
// Create an instance of T and retrieve table name
49-
var instance = new T();
62+
// Check if the type implements IMagicTableBase
63+
if (!typeof(IMagicTableBase).IsAssignableFrom(type))
64+
{
65+
throw new InvalidOperationException($"Type {type.Name} does not implement IMagicTableBase.");
66+
}
67+
68+
// Create an instance dynamically and retrieve the table name
69+
if (Activator.CreateInstance(type) is not IMagicTableBase instance)
70+
{
71+
throw new InvalidOperationException($"Failed to create an instance of {type.Name}.");
72+
}
73+
5074
string tableName = instance.GetTableName();
5175

76+
if (string.IsNullOrWhiteSpace(tableName))
77+
{
78+
throw new InvalidOperationException($"Type {type.Name} returned an invalid table name.");
79+
}
80+
5281
_tableNameCache[type] = tableName;
5382
return tableName;
5483
}
5584

85+
public static bool HasMagicTableInterface(Type type)
86+
{
87+
return typeof(IMagicTableBase).IsAssignableFrom(type);
88+
}
89+
5690
/// <summary>
5791
/// Retrieves all schemas for a given database name.
5892
/// </summary>
59-
public static List<StoreSchema> GetAllSchemas(string databaseName = null)
93+
/* public static List<StoreSchema> GetAllSchemas(string databaseName = null)
6094
{
6195
lock (_lock)
6296
{
@@ -97,7 +131,7 @@ public static List<StoreSchema> GetAllSchemas(string databaseName = null)
97131
98132
return schemas;
99133
}
100-
}
134+
}*/
101135

102136

103137
/// <summary>
@@ -109,12 +143,20 @@ public static StoreSchema GetStoreSchema(Type type)
109143
PropertyMappingCache.EnsureTypeIsCached(type);
110144
EnsureSchemaIsCached(type);
111145

112-
if (!_schemaCache.TryGetValue(type.FullName!, out var schemaAttribute) || schemaAttribute == null)
113-
throw new InvalidOperationException($"Type {type.Name} does not have a [MagicTable] attribute.");
146+
if (!_schemaCache.TryGetValue(type.FullName!, out var cachedType))
147+
throw new InvalidOperationException($"Type {type.Name} is not cached and does not implement IMagicTableBase.");
148+
149+
var instance = Activator.CreateInstance(cachedType) as IMagicTableBase;
150+
if (instance == null)
151+
throw new InvalidOperationException($"Failed to create an instance of {cachedType.Name}.");
152+
153+
var tableName = instance.GetTableName();
154+
if (string.IsNullOrWhiteSpace(tableName))
155+
throw new InvalidOperationException($"Type {cachedType.Name} returned an invalid table name.");
114156

115157
var schema = new StoreSchema
116158
{
117-
TableName = schemaAttribute.SchemaName,
159+
TableName = tableName,
118160
PrimaryKeyAuto = true
119161
};
120162

Magic.IndexedDb/IndexDbManager.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ internal Task DeleteDbAsync(string dbName, CancellationToken cancellationToken =
5252

5353
internal async Task<TKey> AddAsync<T, TKey>(T record, string dbName, CancellationToken cancellationToken = default) where T : class
5454
{
55-
string schemaName = SchemaHelper.GetSchemaName<T>();
55+
string schemaName = SchemaHelper.GetTableName<T>();
5656

5757
StoreRecord<T?> RecordToSend = new StoreRecord<T?>()
5858
{
@@ -89,7 +89,7 @@ internal Task BulkAddRecordAsync<T>(
8989

9090
internal async Task<int> UpdateAsync<T>(T item, string dbName, CancellationToken cancellationToken = default) where T : class
9191
{
92-
string schemaName = SchemaHelper.GetSchemaName<T>();
92+
string schemaName = SchemaHelper.GetTableName<T>();
9393

9494
object? primaryKeyValue = AttributeHelpers.GetPrimaryKeyValue<T>(item);
9595
if (primaryKeyValue is null)
@@ -111,7 +111,7 @@ internal async Task<int> UpdateRangeAsync<T>(
111111
IEnumerable<T> items, string dbName,
112112
CancellationToken cancellationToken = default) where T : class
113113
{
114-
string schemaName = SchemaHelper.GetSchemaName<T>();
114+
string schemaName = SchemaHelper.GetTableName<T>();
115115

116116
var recordsToUpdate = items.Select(item =>
117117
{
@@ -202,7 +202,7 @@ internal IMagicQuery<T> Query<T>(string databaseName, string schemaName) where T
202202

203203
internal async Task DeleteAsync<T>(T item, string dbName, CancellationToken cancellationToken = default) where T : class
204204
{
205-
string schemaName = SchemaHelper.GetSchemaName<T>();
205+
string schemaName = SchemaHelper.GetTableName<T>();
206206

207207
object? primaryKeyValue = AttributeHelpers.GetPrimaryKeyValue<T>(item);
208208

@@ -220,7 +220,7 @@ internal async Task DeleteAsync<T>(T item, string dbName, CancellationToken canc
220220
internal async Task<int> DeleteRangeAsync<T>(
221221
IEnumerable<T> items, string dbName, CancellationToken cancellationToken = default) where T : class
222222
{
223-
string schemaName = SchemaHelper.GetSchemaName<T>();
223+
string schemaName = SchemaHelper.GetTableName<T>();
224224

225225
var keys = items.Select(item =>
226226
{
@@ -259,12 +259,12 @@ internal Task ClearTableAsync(string storeName, string dbName, CancellationToken
259259
/// Wait for response
260260
/// </summary>
261261
/// <returns></returns>
262-
internal Task ClearTableAsync<T>(CancellationToken cancellationToken = default) where T : class
262+
/* internal Task ClearTableAsync<T>(CancellationToken cancellationToken = default) where T : class
263263
{
264-
string schemaName = SchemaHelper.GetSchemaName<T>();
264+
string schemaName = SchemaHelper.GetTableName<T>();
265265
string databaseName = SchemaHelper.GetDefaultDatabaseName<T>();
266266
return ClearTableAsync(schemaName, databaseName, cancellationToken);
267-
}
267+
}*/
268268

269269

270270
}

Magic.IndexedDb/Interfaces/IMagicTableBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public interface IMagicTableBase
1111
string GetTableName();
1212

1313
List<IMagicCompoundIndex>? GetCompoundIndexes();
14-
IMagicCompoundIndex? GetCompoundKey();
14+
IMagicCompoundKey? GetCompoundKey();
1515

1616
// <summary>
1717
/// Set the default database most commonly utilized for this table.

Magic.IndexedDb/Models/StoreSchema.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ public class StoreSchema
2525
/// IndexDB column names that will be automatically indexed.
2626
/// </summary>
2727
public List<string> Indexes { get; set; } = new List<string>();
28-
public List<MagicCompoundExtension> compoundKeys { get; set; } = new List<MagicCompoundExtension>();
28+
//public List<MagicCompoundExtension> compoundKeys { get; set; } = new List<MagicCompoundExtension>();
2929
}
3030
}

0 commit comments

Comments
 (0)