Skip to content

Commit 676f824

Browse files
fixes and fixes
1 parent 3da5a7f commit 676f824

File tree

6 files changed

+104
-91
lines changed

6 files changed

+104
-91
lines changed

Magic.IndexedDb/Helpers/PropertyMappingCache.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ public static SearchPropEntry GetTypeOfTProperties(Type type)
131131

132132
public static bool IsSimpleType(Type type)
133133
{
134+
if (type == null)
135+
return false;
136+
137+
// Handle Nullable<T> types (e.g., Nullable<DateTime> -> DateTime)
138+
if (Nullable.GetUnderlyingType(type) is Type underlyingType)
139+
type = underlyingType;
140+
141+
// Check if primitive, enum, or explicitly in our list
134142
return type.IsPrimitive || type.IsEnum || _simpleTypes.Contains(type);
135143
}
136144

Magic.IndexedDb/IndexDbManager.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,6 @@ private void CollectBinaryExpressions<T>(Expression expression, Expression<Func<
268268
}
269269
else
270270
{
271-
// If the expression is a single condition, create a query for it
272-
var test = expression.ToString();
273-
var tes2t = predicate.ToString();
274-
275271
string jsonQuery = GetJsonQueryFromExpression(Expression.Lambda<Func<T, bool>>(expression, predicate.Parameters));
276272
jsonQueries.Add(jsonQuery);
277273
}
@@ -314,7 +310,8 @@ void TraverseExpression(Expression expression, bool inOrBranch = false)
314310
{
315311
if (expression is BinaryExpression binaryExpression)
316312
{
317-
if (binaryExpression.NodeType == ExpressionType.AndAlso)
313+
if (binaryExpression.NodeType == ExpressionType.AndAlso
314+
|| binaryExpression.NodeType == ExpressionType.NotEqual)
318315
{
319316
TraverseExpression(binaryExpression.Left, inOrBranch);
320317
TraverseExpression(binaryExpression.Right, inOrBranch);
@@ -387,6 +384,20 @@ void AddCondition(Expression expression, bool inOrBranch)
387384
throw new InvalidOperationException($"Unsupported binary expression. Expression: {expression}");
388385
}
389386
}
387+
else if (expression is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Not)
388+
{
389+
if (unaryExpression.Operand is MethodCallExpression innerMethodCall)
390+
{
391+
if (innerMethodCall.Method.DeclaringType == typeof(string) && innerMethodCall.Method.Name == "Equals")
392+
{
393+
var left = innerMethodCall.Object as MemberExpression;
394+
var right = ToConstantExpression(innerMethodCall.Arguments[0]);
395+
396+
AddConditionInternal(left, right, "NotEquals", inOrBranch, false);
397+
return;
398+
}
399+
}
400+
}
390401
else if (expression is MethodCallExpression methodCallExpression)
391402
{
392403
if (methodCallExpression.Method.DeclaringType == typeof(string) &&

Magic.IndexedDb/Magic.IndexedDb.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<PackageReadmeFile>README.md</PackageReadmeFile>
1818
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
1919
<FileVersion>1.01</FileVersion>
20-
<Version>1.0.10</Version>
20+
<Version>1.0.11</Version>
2121
</PropertyGroup>
2222

2323
<ItemGroup>

Magic.IndexedDb/wwwroot/magicDB.js

Lines changed: 42 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,11 @@ export function getStorageEstimate() {
166166
}
167167

168168
export async function where(dbName, storeName, jsonQueries, jsonQueryAdditions, uniqueResults = true) {
169-
170169
const orConditionsArray = jsonQueries.map(query => JSON.parse(query));
171170
const QueryAdditions = JSON.parse(jsonQueryAdditions);
172171

173172
let db = await getDb(dbName);
174-
let table = db.table(storeName); // Corrected: Use Dexie’s table() method
173+
let table = db.table(storeName);
175174

176175
let results = [];
177176

@@ -192,22 +191,28 @@ export async function where(dbName, storeName, jsonQueries, jsonQueryAdditions,
192191
if (!(record[condition.property] <= parsedValue)) return false;
193192
break;
194193
case 'Equal':
194+
if (record[condition.property] === null && condition.value === null) {
195+
return true;
196+
}
195197
if (condition.isString) {
196198
if (condition.caseSensitive) {
197199
if (record[condition.property] !== condition.value) return false;
198200
} else {
199-
if (record[condition.property].toLowerCase() !== condition.value.toLowerCase()) return false;
201+
if (record[condition.property]?.toLowerCase() !== condition.value?.toLowerCase()) return false;
200202
}
201203
} else {
202204
if (record[condition.property] !== parsedValue) return false;
203205
}
204206
break;
205207
case 'NotEqual':
208+
if (record[condition.property] === null && condition.value === null) {
209+
return false;
210+
}
206211
if (condition.isString) {
207212
if (condition.caseSensitive) {
208213
if (record[condition.property] === condition.value) return false;
209214
} else {
210-
if (record[condition.property].toLowerCase() === condition.value.toLowerCase()) return false;
215+
if (record[condition.property]?.toLowerCase() === condition.value?.toLowerCase()) return false;
211216
}
212217
} else {
213218
if (record[condition.property] === parsedValue) return false;
@@ -231,23 +236,19 @@ export async function where(dbName, storeName, jsonQueries, jsonQueryAdditions,
231236

232237
async function processWithCursor(conditions) {
233238
return new Promise((resolve, reject) => {
234-
// Dynamically detect the primary key
235239
let primaryKey = table.schema.primKey.name;
236-
240+
let cursorResults = [];
237241
let request = table.orderBy(primaryKey).each((record) => {
238242
if (applyConditionsToRecord(record, conditions)) {
239-
results.push(record);
243+
cursorResults.push(record);
240244
}
241245
});
242-
243-
request.then(resolve).catch(reject);
246+
request.then(() => resolve(cursorResults)).catch(reject);
244247
});
245248
}
246249

247-
248250
async function processIndexedQuery(conditions) {
249-
let localResults = []; // Store local query results
250-
251+
let localResults = [];
251252
for (const condition of conditions) {
252253
if (table.schema.idxByName[condition.property]) {
253254
let indexQuery = null;
@@ -271,96 +272,66 @@ export async function where(dbName, storeName, jsonQueries, jsonQueryAdditions,
271272
indexQuery = table.where(condition.property).anyOf(condition.value);
272273
break;
273274
}
274-
275275
if (indexQuery) {
276276
let indexedResults = await indexQuery.toArray();
277277
localResults.push(...indexedResults.filter(record => applyConditionsToRecord(record, conditions)));
278278
}
279279
}
280280
}
281-
282281
if (localResults.length === 0) {
283-
await processWithCursor(conditions); // Fallback to cursor-based filtering
284-
} else {
285-
results.push(...localResults); // Append instead of overwriting
282+
localResults = await processWithCursor(conditions);
286283
}
284+
results.push(...localResults);
287285
}
288286

289-
290287
function applyArrayQueryAdditions(results, queryAdditions) {
291-
if (queryAdditions != null) {
292-
for (let i = 0; i < queryAdditions.length; i++) {
293-
const queryAddition = queryAdditions[i];
294-
295-
switch (queryAddition.Name) {
296-
case 'skip':
297-
results = results.slice(queryAddition.IntValue);
298-
break;
299-
case 'take':
300-
results = results.slice(0, queryAddition.IntValue);
301-
break;
302-
case 'takeLast':
303-
results = results.slice(-queryAddition.IntValue).reverse();
304-
break;
305-
case 'orderBy':
306-
results = results.sort((a, b) => a[queryAddition.StringValue] - b[queryAddition.StringValue]);
307-
break;
308-
case 'orderByDescending':
309-
results = results.sort((a, b) => b[queryAddition.StringValue] - a[queryAddition.StringValue]);
310-
break;
311-
default:
312-
console.error('Unsupported query addition for array:', queryAddition.Name);
313-
break;
314-
}
288+
if (queryAdditions) {
289+
if (queryAdditions.some(q => q.Name === 'orderBy')) {
290+
const orderBy = queryAdditions.find(q => q.Name === 'orderBy');
291+
results.sort((a, b) => a[orderBy.StringValue] - b[orderBy.StringValue]);
292+
}
293+
if (queryAdditions.some(q => q.Name === 'orderByDescending')) {
294+
const orderByDescending = queryAdditions.find(q => q.Name === 'orderByDescending');
295+
results.sort((a, b) => b[orderByDescending.StringValue] - a[orderByDescending.StringValue]);
296+
}
297+
if (queryAdditions.some(q => q.Name === 'skip')) {
298+
results = results.slice(queryAdditions.find(q => q.Name === 'skip').IntValue);
299+
}
300+
if (queryAdditions.some(q => q.Name === 'take')) {
301+
results = results.slice(0, queryAdditions.find(q => q.Name === 'take').IntValue);
302+
}
303+
if (queryAdditions.some(q => q.Name === 'takeLast')) {
304+
const takeLastValue = queryAdditions.find(q => q.Name === 'takeLast').IntValue;
305+
results = results.slice(-takeLastValue).reverse();
315306
}
316307
}
317308
return results;
318309
}
319310

320311
async function combineQueries() {
321-
const allQueries = [];
322-
323312
for (const conditions of orConditionsArray) {
324-
325-
const query = await processIndexedQuery(conditions[0]); // Ensure it executes fully
326-
327-
328-
if (query) {
329-
allQueries.push(query);
330-
}
313+
await processIndexedQuery(conditions[0]);
331314
}
332-
333-
334-
if (allQueries.length > 0) {
335-
// Execute all queries in parallel
336-
await Promise.all(allQueries);
337-
338-
339-
// Apply query additions to the combined results
340-
results = applyArrayQueryAdditions(results, QueryAdditions);
341-
342-
343-
if (allQueries.length > 1 && uniqueResults) {
344-
// Make sure the objects in the array are unique
345-
const uniqueObjects = new Set(results.map(obj => JSON.stringify(obj)));
346-
results = Array.from(uniqueObjects).map(str => JSON.parse(str));
347-
}
315+
results = applyArrayQueryAdditions(results, QueryAdditions);
316+
if (uniqueResults) {
317+
const uniqueObjects = new Set(results.map(obj => JSON.stringify(obj)));
318+
results = Array.from(uniqueObjects).map(str => JSON.parse(str));
348319
}
349-
350320
return results;
351321
}
352322

353-
354-
if (orConditionsArray.length > 0)
323+
if (orConditionsArray.length > 0) {
355324
return await combineQueries();
356-
else
325+
} else {
357326
return [];
327+
}
358328
}
359329

360330

361331

362332

363333

334+
364335
async function getDb(dbName) {
365336
if (databases.find(d => d.name == dbName) === undefined) {
366337
console.warn("Blazor.IndexedDB.Framework - Database doesn't exist");

TestWasm/Models/Person.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public class Person
2424

2525
[MagicIndex]
2626
public int TestInt { get; set; }
27+
28+
public DateTime? DateOfBirth { get; set; }
2729

2830
[MagicUniqueIndex("guid")]
2931
public Guid GUIY { get; set; } = Guid.NewGuid();

TestWasm/Pages/Home.razor

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,21 @@
9292
}
9393

9494
@code {
95+
96+
private static readonly Random _random = new Random();
97+
98+
public static int GetRandomYear()
99+
{
100+
return _random.Next(1980, 2024); // Upper bound is exclusive
101+
}
102+
103+
public static DateTime GetDateWithSameMonthDay(int year)
104+
{
105+
DateTime today = DateTime.Today;
106+
return new DateTime(year, today.Month, today.Day);
107+
}
108+
109+
95110
private List<Person> allPeople { get; set; } = new List<Person>();
96111
private IEnumerable<Person> WhereExample { get; set; } = Enumerable.Empty<Person>();
97112
private double storageQuota { get; set; }
@@ -109,15 +124,17 @@
109124
if (!(await manager.GetAllAsync<Person>()).Any())
110125
{
111126
Person[] persons = new Person[] {
112-
new Person { Name = "Zack", TestInt = 9, _Age = 45, GUIY = Guid.NewGuid(), DoNotMapTest = "I buried treasure behind my house", Access=Person.Permissions.CanRead},
113-
new Person { Name = "Luna", TestInt = 9, _Age = 35, GUIY = Guid.NewGuid(), DoNotMapTest = "Jerry is my husband and I had an affair with Bob.", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite},
114-
new Person { Name = "Jerry", TestInt = 9, _Age = 35, GUIY = Guid.NewGuid(), DoNotMapTest = "My wife is amazing", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite|Person.Permissions.CanCreate},
115-
new Person { Name = "Jon", TestInt = 9, _Age = 37, GUIY = Guid.NewGuid(), DoNotMapTest = "I black mail Luna for money because I know her secret", Access = Person.Permissions.CanRead},
116-
new Person { Name = "Jack", TestInt = 9, _Age = 37, GUIY = Guid.NewGuid(), DoNotMapTest = "I have a drug problem", Access = Person.Permissions.CanRead|Person.Permissions.CanWrite},
117-
new Person { Name = "Cathy", TestInt = 9, _Age = 22, GUIY = Guid.NewGuid(), DoNotMapTest = "I got away with reading Bobs diary.", Access = Person.Permissions.CanRead | Person.Permissions.CanWrite},
118-
new Person { Name = "Bob", TestInt = 3 , _Age = 69, GUIY = Guid.NewGuid(), DoNotMapTest = "I caught Cathy reading my diary, but I'm too shy to confront her.", Access = Person.Permissions.CanRead },
119-
new Person { Name = "Alex", TestInt = 3 , _Age = 80, GUIY = Guid.NewGuid(), DoNotMapTest = "I'm naked! But nobody can know!" }
120-
};
127+
new Person { Name = "Zack", DateOfBirth = null, TestInt = 9, _Age = 45, GUIY = Guid.NewGuid(), DoNotMapTest = "I buried treasure behind my house", Access=Person.Permissions.CanRead},
128+
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},
129+
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},
130+
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},
131+
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},
132+
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},
133+
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 },
134+
new Person { Name = "Alex", TestInt = 3 , DateOfBirth = GetDateWithSameMonthDay(GetRandomYear()), _Age = 80, GUIY = Guid.NewGuid(), DoNotMapTest = "I'm naked! But nobody can know!" },
135+
new Person { Name = "Zapoo", DateOfBirth = null, TestInt = 9, _Age = 45, GUIY = Guid.NewGuid(), DoNotMapTest = "I buried treasure behind my house", Access=Person.Permissions.CanRead},
136+
137+
};
121138
await manager.AddRangeAsync(persons);
122139
}
123140

@@ -134,12 +151,16 @@
134151
// || x.Name.Contains("bo", StringComparison.OrdinalIgnoreCase)
135152
// ).OrderBy(x => x._Id).Skip(1).AsAsyncEnumerable()).ToListAsync();
136153
137-
WhereExample = (await manager.Where<Person>(x => x.Name.StartsWith("c", StringComparison.OrdinalIgnoreCase)
138-
|| x.Name.StartsWith("l", StringComparison.OrdinalIgnoreCase)
139-
|| x.Name.StartsWith("j", StringComparison.OrdinalIgnoreCase) && x._Age > 35
140-
|| x.Name.Contains("bo", StringComparison.OrdinalIgnoreCase)
141-
).OrderBy(x => x._Id).Skip(1).ToListAsync());
154+
// WhereExample = (await manager.Where<Person>(x => x.Name.StartsWith("c", StringComparison.OrdinalIgnoreCase)
155+
// || x.Name.StartsWith("l", StringComparison.OrdinalIgnoreCase)
156+
// || x.Name.StartsWith("j", StringComparison.OrdinalIgnoreCase) && x._Age > 35
157+
// || x.Name.Contains("bo", StringComparison.OrdinalIgnoreCase)
158+
// //|| (x.DateOfBirth != null && x.DateOfBirth.GetValueOrDefault().Year < 1980)
159+
// || x.DateOfBirth == null
160+
// ).OrderBy(x => x._Id).Skip(1).ToListAsync());
142161
162+
WhereExample = (await manager.Where<Person>(x => x.DateOfBirth == null
163+
).OrderBy(x => x._Id).Skip(1).Take(6).ToListAsync());
143164

144165
/*
145166
* Still working on allowing nested

0 commit comments

Comments
 (0)