diff --git a/E2eTest/E2eTest.csproj b/E2eTest/E2eTest.csproj index 4f73598..e9e49db 100644 --- a/E2eTest/E2eTest.csproj +++ b/E2eTest/E2eTest.csproj @@ -2,16 +2,16 @@ net9.0 - latest + 13 enable enable - - - - + + + + diff --git a/E2eTestWebApp/E2eTestWebApp.csproj b/E2eTestWebApp/E2eTestWebApp.csproj index 9846fed..a87d15b 100644 --- a/E2eTestWebApp/E2eTestWebApp.csproj +++ b/E2eTestWebApp/E2eTestWebApp.csproj @@ -4,6 +4,7 @@ net9.0 enable enable + 13 diff --git a/Magic.IndexedDb/Exceptions/MagicConstructorException.cs b/Magic.IndexedDb/Exceptions/MagicConstructorException.cs new file mode 100644 index 0000000..b6da8b0 --- /dev/null +++ b/Magic.IndexedDb/Exceptions/MagicConstructorException.cs @@ -0,0 +1,3 @@ +namespace Magic.IndexedDb.Exceptions; + +public class MagicConstructorException(string message) : Exception(message); \ No newline at end of file diff --git a/Magic.IndexedDb/Extensions/MagicJsInvoke.cs b/Magic.IndexedDb/Extensions/MagicJsInvoke.cs index cf6eaf3..a96105c 100644 --- a/Magic.IndexedDb/Extensions/MagicJsInvoke.cs +++ b/Magic.IndexedDb/Extensions/MagicJsInvoke.cs @@ -122,10 +122,10 @@ internal async Task CallInvokeVoidDefaultJsAsync(string modulePath, string funct stream.Position = 0; - var streamRef = new DotNetStreamReference(stream); + using var streamRef = new DotNetStreamReference(stream); // Send to JS - var responseStreamRef = await _jsModule.InvokeAsync("streamedJsHandler", + var responseStreamRef = await _jsModule.InvokeAsync("streamedJsHandler", TimeSpan.FromSeconds(120), streamRef, instanceId, DotNetObjectReference.Create(this), _jsMessageSizeBytes); // 🚀 Convert the stream reference back to JSON in C# @@ -133,6 +133,7 @@ internal async Task CallInvokeVoidDefaultJsAsync(string modulePath, string funct using var reader = new StreamReader(responseStream); string jsonResponse = await reader.ReadToEndAsync(); + await responseStreamRef.DisposeAsync(); return MagicSerializationHelper.DeserializeObject(jsonResponse, settings); } diff --git a/Magic.IndexedDb/Helpers/PropertyMappingCache.cs b/Magic.IndexedDb/Helpers/PropertyMappingCache.cs index cc9750d..efec81d 100644 --- a/Magic.IndexedDb/Helpers/PropertyMappingCache.cs +++ b/Magic.IndexedDb/Helpers/PropertyMappingCache.cs @@ -5,6 +5,7 @@ using System.Collections.Concurrent; using System.Reflection; using System.Text.Json.Serialization; +using Magic.IndexedDb.Exceptions; namespace Magic.IndexedDb.Helpers; @@ -37,12 +38,17 @@ public SearchPropEntry(Type type, Dictionary _proper EnforcePascalCase = false; } - // 🔥 Pick the best constructor: Prefer JsonConstructor, then fall back to a parameterized one, else fallback to parameterless - var jsonConstructor = constructors.FirstOrDefault(c => c.GetCustomAttribute() != null); - if (jsonConstructor == null) + // 🔥 Pick the best constructor: Prefer MagicConstructor, then fall back to a parameterized one, else fallback to parameterless + try + { + Constructor = constructors.SingleOrDefault(c => c.GetCustomAttribute() is not null); + } + catch (InvalidOperationException) { - Constructor = constructors.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault(); + throw new MagicConstructorException("Only one magic constructor is allowed"); } + Constructor ??= constructors.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault(); + HasConstructorParameters = Constructor != null && Constructor.GetParameters().Length > 0; // 🔥 Cache constructor parameter mappings diff --git a/Magic.IndexedDb/Helpers/SchemaHelper.cs b/Magic.IndexedDb/Helpers/SchemaHelper.cs index 9d504d5..b31f524 100644 --- a/Magic.IndexedDb/Helpers/SchemaHelper.cs +++ b/Magic.IndexedDb/Helpers/SchemaHelper.cs @@ -20,6 +20,24 @@ internal static void EnsureSchemaIsCached(Type type) }); } + private static List getAllLoadableTypes() + { + return AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(a => + { + try + { + return a.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + return ex.Types.Where(t => t != null)!; + } + }) + .ToList(); + } + + public static bool ImplementsIMagicTable(Type type) { return type.GetInterfaces().Any(i => i.IsGenericType @@ -28,18 +46,14 @@ public static bool ImplementsIMagicTable(Type type) public static List? GetAllMagicTables() { - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - return assemblies - .SelectMany(a => a.GetTypes()) + return getAllLoadableTypes() .Where(t => t.IsClass && !t.IsAbstract && SchemaHelper.ImplementsIMagicTable(t)) .ToList(); } public static List? GetAllMagicRepositories() { - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - return assemblies - .SelectMany(a => a.GetTypes()) + return getAllLoadableTypes() .Where(t => t.IsClass && !t.IsAbstract && ImplementsIMagicRepository(t)) .ToList(); } diff --git a/Magic.IndexedDb/Interfaces/ITypedArgument.cs b/Magic.IndexedDb/Interfaces/ITypedArgument.cs index 098f65d..ec5c9c5 100644 --- a/Magic.IndexedDb/Interfaces/ITypedArgument.cs +++ b/Magic.IndexedDb/Interfaces/ITypedArgument.cs @@ -5,7 +5,6 @@ namespace Magic.IndexedDb.Interfaces; public interface ITypedArgument { - string Serialize(); // Still needed for some cases JsonElement SerializeToJsonElement(MagicJsonSerializationSettings? settings = null); // Ensures proper object passing string SerializeToJsonString(MagicJsonSerializationSettings? settings = null); } \ No newline at end of file diff --git a/Magic.IndexedDb/LinqTranslation/Extensions/UniversalExpressionBuilder.cs b/Magic.IndexedDb/LinqTranslation/Extensions/UniversalExpressionBuilder.cs index 3b1dc53..1c65381 100644 --- a/Magic.IndexedDb/LinqTranslation/Extensions/UniversalExpressionBuilder.cs +++ b/Magic.IndexedDb/LinqTranslation/Extensions/UniversalExpressionBuilder.cs @@ -744,16 +744,23 @@ private static ConstantExpression ToConst(Expression expr) { expr = StripConvert(expr); // <-- handle Convert wrappers - return expr switch + try { - ConstantExpression c => c, + return expr switch + { + ConstantExpression c => c, - // e.g., new DateTime(...) or anything not marked constant but compile-safe - NewExpression or MemberExpression or MethodCallExpression => - Expression.Constant(Expression.Lambda(expr).Compile().DynamicInvoke()), + // e.g., new DateTime(...) or anything not marked constant but compile-safe + NewExpression or MemberExpression or MethodCallExpression => + Expression.Constant(Expression.Lambda(expr).Compile().DynamicInvoke()), - _ => throw new InvalidOperationException($"Unsupported or non-constant expression: {expr}") - }; + _ => throw new InvalidOperationException($"Unsupported or non-constant expression: {expr}") + }; + } + catch (Exception ex) + { + throw ex; + } } private static Expression StripConvert(Expression expr) diff --git a/Magic.IndexedDb/Magic.IndexedDb.csproj b/Magic.IndexedDb/Magic.IndexedDb.csproj index 946cdc0..fcff6ce 100644 --- a/Magic.IndexedDb/Magic.IndexedDb.csproj +++ b/Magic.IndexedDb/Magic.IndexedDb.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable Magic.IndexedDb @@ -17,7 +17,8 @@ README.md LICENSE.txt 1.01 - 2.0.2 + 2.9.2 + 13 @@ -42,7 +43,7 @@ - - + + diff --git a/Magic.IndexedDb/Models/MagicContractResolver.cs b/Magic.IndexedDb/Models/MagicContractResolver.cs index 38de04b..3c5d7e8 100644 --- a/Magic.IndexedDb/Models/MagicContractResolver.cs +++ b/Magic.IndexedDb/Models/MagicContractResolver.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Concurrent; +using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.Json.Serialization; using Magic.IndexedDb.Helpers; @@ -62,25 +63,41 @@ internal class MagicContractResolver : JsonConverter private object CreateObjectFromDictionary(Type type, Dictionary propertyValues, SearchPropEntry search) { - // 🚀 If there's a constructor with parameters, use it - if (search.ConstructorParameterMappings.Count > 0) + object? obj = null; + List unInitializedProperties = new List(); + // If the constructor set in the SearchPropEntry contains parameters, fill them + if (search.HasConstructorParameters) { var constructorArgs = new object?[search.ConstructorParameterMappings.Count]; foreach (var (paramName, index) in search.ConstructorParameterMappings) { if (propertyValues.TryGetValue(paramName, out var value)) + { constructorArgs[index] = value; + propertyValues.Remove(paramName); + } else - constructorArgs[index] = GetDefaultValue(type.GetProperty(paramName)?.PropertyType ?? typeof(object)); + { + constructorArgs[index] = + GetDefaultValue(type.GetProperty(paramName)?.PropertyType ?? typeof(object)); + } } - return search.InstanceCreator(constructorArgs) ?? throw new InvalidOperationException($"Failed to create instance of type {type.Name}."); + obj = search.InstanceCreator(constructorArgs); + } + else + { + // 🚀 Use parameterless constructor + obj = search.InstanceCreator([]); + } + + if (obj is null) + { + throw new InvalidOperationException($"Failed to create instance of type {type.Name}."); } - // 🚀 Use parameterless constructor - var obj = search.InstanceCreator(Array.Empty()) ?? throw new InvalidOperationException($"Failed to create instance of type {type.Name}."); - // 🚀 Assign property values + // 🚀 Assign property values (to properties not passed to constructor) foreach (var (propName, value) in propertyValues) { if (search.propertyEntries.TryGetValue(propName, out var propEntry)) @@ -342,6 +359,12 @@ private bool SerializeIEnumerable(Utf8JsonWriter writer, object? value, JsonSeri continue; } + if (item is IEnumerable nestedEnumerable && item.GetType() != typeof(string)) + { + SerializeIEnumerable(writer, nestedEnumerable, options); + continue; + } + if (item != null) { Type itemType = item.GetType(); @@ -374,7 +397,8 @@ private void WriteSimpleType(Utf8JsonWriter writer, object value) switch (value) { case string str: - writer.WriteStringValue(str); + str = str.Replace("\"", "\\\""); + writer.WriteRawValue("\"" + str + "\"", true); break; case bool b: writer.WriteBooleanValue(b); @@ -397,6 +421,9 @@ private void WriteSimpleType(Utf8JsonWriter writer, object value) case Guid guid: writer.WriteStringValue(guid.ToString()); break; + case Enum e: + writer.WriteNumberValue(((IConvertible)e).ToInt32(null)); + break; default: JsonSerializer.Serialize(writer, value); break; diff --git a/Magic.IndexedDb/Models/TypedArgument.cs b/Magic.IndexedDb/Models/TypedArgument.cs index 6074336..adfd757 100644 --- a/Magic.IndexedDb/Models/TypedArgument.cs +++ b/Magic.IndexedDb/Models/TypedArgument.cs @@ -13,11 +13,6 @@ public TypedArgument(T? value) Value = value; } - public string Serialize() - { - return MagicSerializationHelper.SerializeObject(Value); - } - public JsonElement SerializeToJsonElement(MagicJsonSerializationSettings? settings = null) { return MagicSerializationHelper.SerializeObjectToJsonElement(Value, settings); diff --git a/Magic.IndexedDb/SchemaAnnotations/MagicConstructorAttribute.cs b/Magic.IndexedDb/SchemaAnnotations/MagicConstructorAttribute.cs new file mode 100644 index 0000000..9dd5430 --- /dev/null +++ b/Magic.IndexedDb/SchemaAnnotations/MagicConstructorAttribute.cs @@ -0,0 +1,6 @@ +namespace Magic.IndexedDb.SchemaAnnotations; + +/// +/// Sets the preferred constructor for serialization for MagicDB +/// +public class MagicConstructorAttribute : Attribute; \ No newline at end of file diff --git a/Magic.IndexedDb/wwwroot/magicDB.js b/Magic.IndexedDb/wwwroot/magicDB.js index 7a79fa8..11c9d42 100644 --- a/Magic.IndexedDb/wwwroot/magicDB.js +++ b/Magic.IndexedDb/wwwroot/magicDB.js @@ -3,6 +3,7 @@ /// import Dexie from "./dexie/dexie.js"; import { magicQueryAsync, magicQueryYield } from "./magicLinqToIndexedDb.js"; +import {debugLog} from "./utilities/utilityHelpers.js"; /** * @typedef {Object} DatabasesItem * @property {string} name @@ -77,7 +78,7 @@ export function listOpenDatabases() { export function createDb(dbStore) { - console.log("Debug: Received dbStore in createDb", dbStore); + debugLog("Received dbStore in createDb", dbStore); if (!dbStore || !dbStore.name) { console.error("Blazor.IndexedDB.Framework - Invalid dbStore provided"); @@ -144,7 +145,7 @@ export function createDb(dbStore) { stores[schema.tableName] = def; } - console.log("Dexie Store Definition:", stores); + debugLog("Dexie Store Definition:", stores); db.version(dbStore.version).stores(stores); @@ -178,7 +179,7 @@ export function closeAll() { databases.forEach((entry, dbName) => { entry.db.close(); entry.isOpen = false; - console.log(`Database ${dbName} closed.`); + debugLog(`Database ${dbName} closed.`); }); } @@ -205,7 +206,7 @@ export async function deleteDb(dbName) { } await Dexie.delete(dbName); - console.log(`Database '${dbName}' deleted.`); + debugLog(`Database '${dbName}' deleted.`); } catch (deleteErr) { console.error(`deleteDb: Failed to delete DB '${dbName}'`, deleteErr); } @@ -297,7 +298,7 @@ export async function deleteAllDatabases() { for (const dbName of databases.keys()) { await deleteDb(dbName); } - console.log("All databases deleted."); + debugLog("All databases deleted."); } @@ -457,7 +458,7 @@ export async function bulkDelete(dbName, storeName, items) { items.map(item => getKeyArrayForDelete(dbName, storeName, item)) ); - console.log('Keys to delete:', formattedKeys); + debugLog('Keys to delete:', formattedKeys); await table.bulkDelete(formattedKeys); return items.length; } catch (e) { diff --git a/Magic.IndexedDb/wwwroot/magicMigration.js b/Magic.IndexedDb/wwwroot/magicMigration.js index 72842c6..8b5f7cf 100644 --- a/Magic.IndexedDb/wwwroot/magicMigration.js +++ b/Magic.IndexedDb/wwwroot/magicMigration.js @@ -1,10 +1,12 @@ +import {debugLog} from "./utilities/utilityHelpers.js"; + export class MagicMigration { constructor(db) { this.db = db; } Initialize() { - console.log("Using Dexie from MagicDB:", this.db); + debugLog("Using Dexie from MagicDB:", this.db); // You can now do any Dexie operations here } } diff --git a/TestBase/Data/PersonData.cs b/TestBase/Data/PersonData.cs index 256a244..6fb76c9 100644 --- a/TestBase/Data/PersonData.cs +++ b/TestBase/Data/PersonData.cs @@ -6,7 +6,7 @@ public static class PersonData { public static Person[] persons = [ - new Person { _Id = 1, Name = "Zack", DateOfBirth = null, TestInt = 9, _Age = 45, GUIY = Guid.NewGuid(), DoNotMapTest = "I buried treasure behind my house", Access=Person.Permissions.CanRead}, + new Person { _Id = 1, Name = "Zack", DateOfBirth = null, TestInt = 9, _Age = 45, GUIY = Guid.NewGuid(), DoNotMapTest = "I buried treasure behind my house", Access=Person.Permissions.CanRead, Secret = new String('a', 45)}, new Person { _Id = 2, Name = "Luna", TestInt = 9, DateOfBirth = new DateTime(1980, 1, 1), _Age = 35, GUIY = Guid.NewGuid(), DoNotMapTest = "Jerry is my husband and I had an affair with Bob.", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite}, new Person { _Id = 3, Name = "Jerry", TestInt = 9, DateOfBirth = new DateTime(1981, 1, 1), _Age = 35, GUIY = Guid.NewGuid(), DoNotMapTest = "My wife is amazing", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite|Person.Permissions.CanCreate}, new Person { _Id = 4, Name = "Jamie", TestInt = 9, DateOfBirth = new DateTime(1982, 1, 1), _Age = 35, GUIY = Guid.NewGuid(), DoNotMapTest = "My wife is amazing", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite|Person.Permissions.CanCreate}, diff --git a/TestBase/Models/Person.cs b/TestBase/Models/Person.cs index 8e5afd3..1c7c5f9 100644 --- a/TestBase/Models/Person.cs +++ b/TestBase/Models/Person.cs @@ -14,7 +14,8 @@ public class Nested public class Person : MagicTableTool, IMagicTable { - [JsonConstructor] + + [MagicConstructor] public Person() { DoNotMapTest2 = "Test"; @@ -22,7 +23,7 @@ public Person() public Person(int _Id) { - DoNotMapTest2 = _Id.ToString(); + this._Id = _Id; } public List GetCompoundIndexes() => diff --git a/TestBase/TestBase.csproj b/TestBase/TestBase.csproj index 4924a89..46ef327 100644 --- a/TestBase/TestBase.csproj +++ b/TestBase/TestBase.csproj @@ -1,9 +1,10 @@  - net8.0 + net9.0 enable enable + 13 diff --git a/TestServer/TestServer.Client/TestServer.Client.csproj b/TestServer/TestServer.Client/TestServer.Client.csproj index 1786b3a..7fe7f14 100644 --- a/TestServer/TestServer.Client/TestServer.Client.csproj +++ b/TestServer/TestServer.Client/TestServer.Client.csproj @@ -1,4 +1,4 @@ - + net9.0 @@ -6,11 +6,12 @@ enable true Default + 13 - - + + diff --git a/TestServer/TestServer/TestServer.csproj b/TestServer/TestServer/TestServer.csproj index 47915bb..a2ee381 100644 --- a/TestServer/TestServer/TestServer.csproj +++ b/TestServer/TestServer/TestServer.csproj @@ -1,17 +1,18 @@ - + net9.0 enable enable + 13 - - + + diff --git a/TestWasm/Layout/NavMenu.razor b/TestWasm/Layout/NavMenu.razor index aeddca1..9e8c6c2 100644 --- a/TestWasm/Layout/NavMenu.razor +++ b/TestWasm/Layout/NavMenu.razor @@ -14,16 +14,6 @@ Home - - diff --git a/TestWasm/Models/DbNames.cs b/TestWasm/Models/DbNames.cs deleted file mode 100644 index 31f1d41..0000000 --- a/TestWasm/Models/DbNames.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace TestWasm.Models; - -public static class DbNames -{ - public const string Client = "client"; -} \ No newline at end of file diff --git a/TestWasm/Models/Person.cs b/TestWasm/Models/Person.cs deleted file mode 100644 index 20cd2a5..0000000 --- a/TestWasm/Models/Person.cs +++ /dev/null @@ -1,97 +0,0 @@ -using Magic.IndexedDb; - -using Magic.IndexedDb.SchemaAnnotations; -using TestWasm.Repository; -using static TestWasm.Models.Person; - -namespace TestWasm.Models; - -public class Nested -{ - public string Value { get; set; } = "abc"; -} - - -public class Person : MagicTableTool, IMagicTable -{ - public List GetCompoundIndexes() => - new List() { - CreateCompoundIndex(x => x.TestIntStable2, x => x.Name) - }; - - //public IMagicCompoundKey GetKeys() => - // CreateCompoundKey(x => x.TestIntStable2, x => x.TestIntStable); - - public IMagicCompoundKey GetKeys() => - CreatePrimaryKey(x => x._Id, true); - - public string GetTableName() => "Person"; - public IndexedDbSet GetDefaultDatabase() => IndexDbContext.Client; - public DbSets Databases { get; } = new(); - public sealed class DbSets - { - public readonly IndexedDbSet Client = IndexDbContext.Client; - public readonly IndexedDbSet Employee = IndexDbContext.Employee; - } - - - public int TestIntStable { get; set; } - public int TestIntStable2 { get; set; } = 10; - - public Nested Nested { get; set; } = new Nested(); - - [MagicName("_id")] - public int _Id { get; set; } - - [MagicName("guid1")] - public Guid Guid1 { get; set; } = new Guid(); - - [MagicName("guid2")] - public Guid Guid2 { get; set; } = new Guid(); - - [MagicIndex] - public string Name { get; set; } - - [MagicName("Age")] - public int _Age { get; set; } - - [MagicIndex("TestInt")] - public int TestInt { get; set; } - - public DateTime? DateOfBirth { get; set; } - - [MagicUniqueIndex("guid")] - public Guid GUIY { get; set; } = Guid.NewGuid(); - public string Secret { get; set; } - - [MagicNotMapped] - public string DoNotMapTest { get; set; } - - [MagicNotMapped] - public static string DoNotMapTest2 { get; set; } - - [MagicNotMapped] - public string SecretDecrypted { get; set; } - - - public object Payload { get; set; } = new { Property = "test" }; - - private bool testPrivate { get; set; } = false; - - public bool GetTest() - { - return true; - } - - [Flags] - public enum Permissions - { - None = 0, - CanRead = 1, - CanWrite = 1 << 1, - CanDelete = 1 << 2, - CanCreate = 1 << 3 - } - - public Permissions Access { get; set; } -} \ No newline at end of file diff --git a/TestWasm/Pages/Counter.razor b/TestWasm/Pages/Counter.razor deleted file mode 100644 index ef23cb3..0000000 --- a/TestWasm/Pages/Counter.razor +++ /dev/null @@ -1,18 +0,0 @@ -@page "/counter" - -Counter - -

Counter

- -

Current count: @currentCount

- - - -@code { - private int currentCount = 0; - - private void IncrementCount() - { - currentCount++; - } -} diff --git a/TestWasm/Pages/Home.razor b/TestWasm/Pages/Home.razor index 396097c..613ca2a 100644 --- a/TestWasm/Pages/Home.razor +++ b/TestWasm/Pages/Home.razor @@ -1,12 +1,10 @@ @page "/" @using Magic.IndexedDb -@using TestWasm.Models -@using TestWasm.Repository +@using TestBase.Models +@using TestBase.Repository @using System.Linq; @using TestBase.Helpers -@using TestBase.Models @using TestWasm.Share -@using Person = TestWasm.Models.Person @inject IMagicIndexedDb _MagicDb @@ -220,68 +218,7 @@ IndexOrderingProperties = new List> { personQuery = await _MagicDb.Query(); await personQuery.ClearTable(); - // Choose an assigned database to Person with strictly typed enforced connected Db's. - IMagicQuery employeeDbQuery = await _MagicDb.Query(x => x.Databases.Client); - - // Not implemented yet - // // // Highly not suggested, but you're allowed to target databases not assigned to the Person table - // IMagicQuery animalDbQuery = await _MagicDb.Query(IndexDbContext.Animal); - - // // // DO NOT DO THIS! I only am allowing this for maximum flexibility but this is very dangerous. - // IMagicQuery unassignedDbQuery = await _MagicDb.QueryOverride("DbName", "SchemaName"); - - - - - Person[] persons = new Person[] { - new Person { Name = "Zack", DateOfBirth = null, TestInt = 9, _Age = 45, GUIY = Guid.NewGuid(), DoNotMapTest = "I buried treasure behind my house", Access=Person.Permissions.CanRead}, - new Person { Name = "Luna", TestInt = 9, DateOfBirth = GetDateWithSameMonthDay(GetRandomYear()), _Age = 35, GUIY = Guid.NewGuid(), DoNotMapTest = "Jerry is my husband and I had an affair with Bob.", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite}, - new Person { Name = "Jerry", TestInt = 9, DateOfBirth = GetDateWithSameMonthDay(GetRandomYear()), _Age = 35, GUIY = Guid.NewGuid(), DoNotMapTest = "My wife is amazing", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite|Person.Permissions.CanCreate}, - new Person { Name = "Jamie", TestInt = 9, DateOfBirth = GetDateWithSameMonthDay(GetRandomYear()), _Age = 35, GUIY = Guid.NewGuid(), DoNotMapTest = "My wife is amazing", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite|Person.Permissions.CanCreate}, - new Person { Name = "James", TestInt = 9, DateOfBirth = GetDateWithSameMonthDay(GetRandomYear()), _Age = 35, GUIY = Guid.NewGuid(), DoNotMapTest = "My wife is amazing", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite|Person.Permissions.CanCreate}, - new Person { Name = "Jack", TestInt = 9, DateOfBirth = GetDateWithSameMonthDay(GetRandomYear()), _Age = 35, GUIY = Guid.NewGuid(), DoNotMapTest = "My wife is amazing", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite|Person.Permissions.CanCreate}, - new Person { Name = "Jon", TestInt = 9, DateOfBirth = GetDateWithSameMonthDay(GetRandomYear()), _Age = 37, GUIY = Guid.NewGuid(), DoNotMapTest = "I black mail Luna for money because I know her secret", Access = Person.Permissions.CanRead}, - new Person { Name = "Jack", TestInt = 9, DateOfBirth = GetDateWithSameMonthDay(GetRandomYear()), _Age = 37, GUIY = Guid.NewGuid(), DoNotMapTest = "I have a drug problem", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite}, - new Person { Name = "Cathy", TestInt = 9, DateOfBirth = GetDateWithSameMonthDay(GetRandomYear()), _Age = 22, GUIY = Guid.NewGuid(), DoNotMapTest = "I got away with reading Bobs diary.", Access = Person.Permissions.CanRead | Person.Permissions.CanWrite}, - new Person { Name = "Bob", TestInt = 3 , DateOfBirth = GetDateWithSameMonthDay(GetRandomYear()), _Age = 69, GUIY = Guid.NewGuid(), DoNotMapTest = "I caught Cathy reading my diary, but I'm too shy to confront her.", Access = Person.Permissions.CanRead }, - new Person { Name = "Alex", TestInt = 3 , DateOfBirth = null, _Age = 80, GUIY = Guid.NewGuid(), DoNotMapTest = "I'm naked! But nobody can know!" }, - new Person { Name = "Zapoo", DateOfBirth = null, TestInt = 9, _Age = 45, GUIY = Guid.NewGuid(), DoNotMapTest = "I buried treasure behind my house", Access=Person.Permissions.CanRead}, - - new Person { Name = "Sarah", TestInt = -1, _Age = 30, GUIY = Guid.NewGuid(), DoNotMapTest = "I hate my job", Access=Person.Permissions.CanRead}, - new Person { Name = "Michael", TestInt = 15, _Age = 50, GUIY = Guid.NewGuid(), DoNotMapTest = "I'm hiding a big secret", Access=Person.Permissions.CanRead | Person.Permissions.CanWrite}, - new Person { Name = "Tommy", TestInt = 7, _Age = 12, GUIY = Guid.NewGuid(), DoNotMapTest = "I am just a kid" }, - new Person { Name = "Grace", TestInt = 3, _Age = 90, GUIY = Guid.NewGuid(), DoNotMapTest = "I have seen the world" }, - new Person { Name = "Xylophone", TestInt = 9, _Age = 27, GUIY = Guid.NewGuid(), DoNotMapTest = "I have the weirdest name" }, - new Person { Name = "Yasmine", TestInt = 9, _Age = 40, GUIY = Guid.NewGuid(), DoNotMapTest = null }, - // Additional test case persons to stress-test LINQ validation - new Person { Name = "Alicia", TestInt = 42, _Age = 16, GUIY = Guid.NewGuid(), DoNotMapTest = "I just got my driver's license" }, - new Person { Name = "Ben", TestInt = 0, _Age = 25, GUIY = Guid.NewGuid(), DoNotMapTest = "I have no TestInt value" }, - new Person { Name = "Clara", TestInt = 100, _Age = 65, GUIY = Guid.NewGuid(), DoNotMapTest = "I retired last week", Access = Person.Permissions.CanRead | Person.Permissions.CanWrite }, - new Person { Name = "Danny", TestInt = 9, _Age = 40, GUIY = Guid.NewGuid(), DoNotMapTest = null }, // Null handling - new Person { Name = "Elliot", TestInt = -20, _Age = 55, GUIY = Guid.NewGuid(), DoNotMapTest = "My test int is negative" }, - new Person { Name = "Fiona", TestInt = 11, _Age = 33, GUIY = Guid.NewGuid(), DoNotMapTest = "I like puzzles" }, - new Person { Name = "George", TestInt = 8, _Age = 72, GUIY = Guid.NewGuid(), DoNotMapTest = "I fought in a war", Access = Person.Permissions.CanRead | Person.Permissions.CanWrite | Person.Permissions.CanCreate }, - new Person { Name = "Henry", TestInt = 99, _Age = 29, GUIY = Guid.NewGuid(), DoNotMapTest = "I almost made it to 100 TestInt" }, - new Person { Name = "Isla", TestInt = 2, _Age = 18, GUIY = Guid.NewGuid(), DoNotMapTest = "I just turned into an adult" }, - new Person { Name = "Jackie", TestInt = 75, _Age = 60, GUIY = Guid.NewGuid(), DoNotMapTest = "I love cooking" }, - new Person { Name = "Kevin", TestInt = 5, _Age = 48, GUIY = Guid.NewGuid(), DoNotMapTest = "I own a small business" }, - new Person { Name = "Liam", TestInt = 9, _Age = 55, GUIY = Guid.NewGuid(), DoNotMapTest = "I just became a grandfather" }, - new Person { Name = "Mona", TestInt = 88, _Age = 35, GUIY = Guid.NewGuid(), DoNotMapTest = "I am a detective", Access = Person.Permissions.CanRead | Person.Permissions.CanWrite }, - new Person { Name = "Nathan", TestInt = 7, _Age = 27, GUIY = Guid.NewGuid(), DoNotMapTest = "I play guitar" }, - new Person { Name = "Olivia", TestInt = 13, _Age = 45, GUIY = Guid.NewGuid(), DoNotMapTest = "I run marathons" }, - new Person { Name = "Patrick", TestInt = 3, _Age = 52, GUIY = Guid.NewGuid(), DoNotMapTest = "I work in IT" }, - new Person { Name = "Quinn", TestInt = 22, _Age = 42, GUIY = Guid.NewGuid(), DoNotMapTest = "I design board games" }, - new Person { Name = "Rachel", TestInt = 77, _Age = 36, GUIY = Guid.NewGuid(), DoNotMapTest = "I am a pilot" }, - new Person { Name = "Steve", TestInt = 9, _Age = 38, GUIY = Guid.NewGuid(), DoNotMapTest = "I am an engineer" }, - new Person { Name = "Tina", TestInt = 3, _Age = 68, GUIY = Guid.NewGuid(), DoNotMapTest = "I just got my pension" }, - new Person { Name = "Uma", TestInt = 14, _Age = 39, GUIY = Guid.NewGuid(), DoNotMapTest = "I teach yoga" }, - new Person { Name = "Victor", TestInt = 6, _Age = 31, GUIY = Guid.NewGuid(), DoNotMapTest = "I am an artist" }, - new Person { Name = "Wendy", TestInt = 50, _Age = 50, GUIY = Guid.NewGuid(), DoNotMapTest = "My age matches my test int" }, - new Person { Name = "Xander", TestInt = 19, _Age = 21, GUIY = Guid.NewGuid(), DoNotMapTest = "I am a college student" }, - new Person { Name = "Yara", TestInt = 90, _Age = 32, GUIY = Guid.NewGuid(), DoNotMapTest = "I work in finance" }, - new Person { Name = "Zane", TestInt = 101, _Age = 47, DateOfBirth = new DateTime(2020, 2, 10), GUIY = Guid.NewGuid(), DoNotMapTest = "I love motorcycles" }, - - }; + var persons = TestBase.Data.PersonData.persons; var guiys = new HashSet(); var count = 0; @@ -299,23 +236,7 @@ IndexOrderingProperties = new List> { Console.WriteLine($"Duplicate GUID found! {p.Name} - {p.GUIY}"); } } - - //var storageInfo = await _MagicDb.GetStorageEstimateAsync(); - //storageQuota = storageInfo.QuotaInMegabytes; - //storageUsage = storageInfo.UsageInMegabytes; - - - - - // WhereExample = await (manager.Where(x => x.Name.StartsWith("c", StringComparison.OrdinalIgnoreCase) - // || x.Name.StartsWith("l", StringComparison.OrdinalIgnoreCase) - // || x.Name.StartsWith("j", StringComparison.OrdinalIgnoreCase) && x._Age > 35 - // || x.Name.Contains("bo", StringComparison.OrdinalIgnoreCase) - // ).OrderBy(x => x._Id).Skip(1).AsAsyncEnumerable()).ToListAsync(); - - //IMagicQuery personQuery = manager.Query(); - - //await personQuery.AddRangeAsync(persons); + foreach (var p in persons.OrderBy(x => x._Id)) { await personQuery.AddAsync(p); @@ -324,79 +245,6 @@ IndexOrderingProperties = new List> { allPeople = await personQuery.ToListAsync(); - StateHasChanged(); - - @* //await manager.ClearTableAsync(); - var db = await _MagicDb.Database(IndexDbContext.Client); - //await db.DeleteAsync(); - await db.CloseAsync(); - bool doesExist = await db.DoesExistAsync(); - bool isOpen = await db.IsOpenAsync(); - await db.OpenAsync(); - bool isOpenNow = await db.IsOpenAsync(); *@ - - var d = new DateTime(); - var asdf = d.DayOfWeek; - var asdf2 = d.DayOfYear; - - - // I know the validation of "allPeople" targets differently but I know this is the right result. - // This is a weird .NET memory grab weirdess. - - - - // var blueprint = new QueryTestBlueprint - // { - // WherePredicates = [x => x.TestInt == 9], - // OrderBys = [x => x._Age], - // OrderByDescendings = [x => x._Age], - // TakeValues = [2], - // TakeLastValues = [1], - // SkipValues = [1], - // }; - - // var tests = MagicQueryPathWalker.GenerateAllPaths(personQuery, allPeople, blueprint); - - // foreach (var test in tests) - // { - // try - // { - // var executedTestDb = await test.ExecuteDb(); - // var mem = test.ExecuteInMemory(); - // RunTest(test.Name, executedTestDb, mem); - // } - // catch (Exception ex) - // { - // //RunTest(test.Name, [], [], $"Exception: {ex.Message}"); - // } - // } - - - // RunTest("Test Test", - // await personQuery.Cursor(x => x.TestInt == 9).OrderBy(x => x._Age).Skip(1).ToListAsync(), - // allPeople.Where(x => x.TestInt == 9).OrderBy(x => x._Age).ThenBy(x => x._Id).Skip(1)); - - // var asdfdffddf = await personQuery.Cursor(x => x.TestInt == 9).OrderBy(x => x._Age).Skip(1).ToListAsync(); - // RunTest("Test Test", - // await personQuery.Cursor(x => x.TestInt == 9).OrderBy(x => x._Age).Skip(1).ToListAsync(), - // allPeople.Where(x => x.TestInt == 9).OrderBy(x => x._Age).ThenBy(x => x._Id).Skip(1)); - - var result1 = await personQuery.Take(2).ToListAsync(); - - - var result2 = allPeople.OrderBy(x => x._Id).Take(2).ToList(); - - - - - // ends with not yet supported - // // 🔀 Complex AND/OR Mix (Nested Multiple Layers) - // RunTest("Deeply Nested AND within OR", - // await personQuery.Where(x => (x._Age > 30 && (x.TestInt == 9 || x.Name.StartsWith("J"))) || (x.TestInt == 3 && x.Name.EndsWith("b", StringComparison.OrdinalIgnoreCase))) - // .ToListAsync(), - // allPeople.Where(x => (x._Age > 30 && (x.TestInt == 9 || x.Name.StartsWith("J"))) || (x.TestInt == 3 && x.Name.EndsWith("b", StringComparison.OrdinalIgnoreCase)))); - - StateHasChanged(); } catch (Exception ex) diff --git a/TestWasm/Pages/Weather.razor b/TestWasm/Pages/Weather.razor deleted file mode 100644 index 8a083fc..0000000 --- a/TestWasm/Pages/Weather.razor +++ /dev/null @@ -1,57 +0,0 @@ -@page "/weather" -@inject HttpClient Http - -Weather - -

Weather

- -

This component demonstrates fetching data from the server.

- -@if (forecasts == null) -{ -

Loading...

-} -else -{ - - - - - - - - - - - @foreach (var forecast in forecasts) - { - - - - - - - } - -
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
-} - -@code { - private WeatherForecast[]? forecasts; - - protected override async Task OnInitializedAsync() - { - forecasts = await Http.GetFromJsonAsync("sample-data/weather.json"); - } - - public class WeatherForecast - { - public DateOnly Date { get; set; } - - public int TemperatureC { get; set; } - - public string? Summary { get; set; } - - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - } -} diff --git a/TestWasm/Repository/IndexDbContext.cs b/TestWasm/Repository/IndexDbContext.cs deleted file mode 100644 index 59a007d..0000000 --- a/TestWasm/Repository/IndexDbContext.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Magic.IndexedDb; -using Magic.IndexedDb.Interfaces; - -namespace TestWasm.Repository; - -public class IndexDbContext : IMagicRepository -{ - public static readonly IndexedDbSet Client = new ("Client"); - public static readonly IndexedDbSet Employee = new ("Employee"); - public static readonly IndexedDbSet Animal = new ("Animal"); -} \ No newline at end of file diff --git a/TestWasm/Share/PanelCustomTests.razor b/TestWasm/Share/PanelCustomTests.razor index 852d74e..28b8ec4 100644 --- a/TestWasm/Share/PanelCustomTests.razor +++ b/TestWasm/Share/PanelCustomTests.razor @@ -1,8 +1,6 @@ @using Magic.IndexedDb @using TestBase.Helpers @using TestBase.Models -@using TestWasm.Models -@using Person = TestWasm.Models.Person @inject IMagicIndexedDb _MagicDb @@ -16,33 +14,6 @@ - - Custom Person table tests: - - @foreach (var (testName, response, countResults) in TestResults) - { -
- @if (response.Success) - { - ✅ @testName @($" - {countResults}") - } - else - { - ❌ @testName @($"- {countResults}") - - @if (!string.IsNullOrWhiteSpace(response.Message)) - { - var messages = response.Message.Split('\n', StringSplitOptions.RemoveEmptyEntries); - foreach (var message in messages) - { -
🔍 @message
- } - } - } -
- } -
- @foreach (var (testName, response, countResults) in TestResults) {
diff --git a/TestWasm/TestWasm.csproj b/TestWasm/TestWasm.csproj index 32cb0e1..f1eb202 100644 --- a/TestWasm/TestWasm.csproj +++ b/TestWasm/TestWasm.csproj @@ -1,15 +1,16 @@ - + - net8.0 + net9.0 enable enable + 13 - - - + + +