void IComplexQueryEntity.UtilizeComplexQueryResult(ComplexQueryResult result) { ((IEmailEntity)this).Email = result .OfType <Contact>() .FirstOrDefault(c => c.ContactID == this.ContactID) ?.Email; }
void IComplexQueryCachedEntity.SaveCache(ComplexQueryResult result) { JsonFileCacheManager.Instance.SaveCache( nameof(Case) + '.' + nameof(IComplexQueryCachedEntity), result .OfType <Contact>() .Select(c => new { ContactID = c.ContactID.Value, Email = c.Email.Value }) .Where(c => !c.Email.IsNullOrEmpty())); }
internal QueryResult QueryNoLINQ(QueryInfo info, CLR.HashSet <string> tagsToExclude = null) { var timer = Stopwatch.StartNew(); TagByQueryLookup queryInfo = GetTagByQueryLookup(info.Type); ThrowIfInvalidParameters(info.Tag, info.PageSize, queryInfo); ThrowIfInvalidParameters(info.OtherTag, info.PageSize, queryInfo); ComplexQueryResult queryResult = null; switch (info.Operator) { case "AND": queryResult = AndQuery(queryInfo[info.Tag], queryInfo[info.OtherTag], info.PageSize, info.Skip, tagsToExclude); break; case "AND-NOT": queryResult = AndNotQuery(queryInfo[info.Tag], queryInfo[info.OtherTag], info.PageSize, info.Skip, tagsToExclude); break; case "OR": queryResult = OrQuery(queryInfo[info.Tag], queryInfo[info.OtherTag], info.PageSize, info.Skip, tagsToExclude); break; case "OR-NOT": //"i.e. .net+or+jquery-" queryResult = OrNotQuery(queryInfo[info.Tag], queryInfo[info.OtherTag], queryInfo[TagServer.ALL_TAGS_KEY], info.PageSize, info.Skip, tagsToExclude); break; // TODO Work out what a "NOT" query really means, at the moment it's the same as "AND-NOT"?! //case "NOT": // queryResult = NotQuery(queryInfo[info.Tag], queryInfo[info.OtherTag], info.PageSize, info.Skip, tagsToExclude); // break; default: throw new InvalidOperationException(string.Format("Invalid operator specified: {0}", info.Operator ?? "<NULL>")); } timer.Stop(); Results.AddData(timer.Elapsed.TotalMilliseconds.ToString("#.##")); Logger.Log("NO LINQ Boolean Query: \"{0}\" {1} \"{2}\", pageSize = {3:N0}, skip = {4:N0}, took {5} ({6:N2} ms) NO LINQ", info.Tag, info.Operator, info.OtherTag, info.PageSize, info.Skip, timer.Elapsed, timer.Elapsed.TotalMilliseconds); Logger.Log("Got {0:N0} results in total, baseQueryCounter = {1:N0}, itemsSkipped = {2:N0}, excludedCounter = {3:N0} ({4} tags to be excluded)", queryResult.Results.Count(), queryResult.BaseQueryCounter, queryResult.ItemsSkipped, queryResult.ExcludedCounter, tagsToExclude != null ? tagsToExclude.Count.ToString("N0") : "NO"); return(new QueryResult { Questions = queryResult.Results, Counters = new Dictionary <string, int> { { "BaseQueryCounter", queryResult.BaseQueryCounter }, { "ItemsSkipped", queryResult.ItemsSkipped }, { "ExcludedCounter", queryResult.ExcludedCounter } } }); }
ComplexQueryResult AndNotQuery(int[] tag1Ids, int[] tag2Ids, int pageSize, int skip, CLR.HashSet <string> tagsToExclude = null) { var queryResult = new ComplexQueryResult { Results = new List <Question>(pageSize), BaseQueryCounter = 0, ItemsSkipped = 0, ExcludedCounter = 0 }; // https://github.com/ungood/EduLinq/blob/master/Edulinq/Except.cs#L26-L40 var notHashSet = cache.Value.GetCachedHashSet(tag2Ids); foreach (var item in tag1Ids) { if (queryResult.Results.Count >= pageSize) { break; } queryResult.BaseQueryCounter++; if (tagsToExclude != null && questions[item].Tags.Any(t => tagsToExclude.Contains(t))) { queryResult.ExcludedCounter++; } else if (notHashSet.Add(item)) { if (queryResult.ItemsSkipped >= skip) { queryResult.Results.Add(questions[item]); } else { queryResult.ItemsSkipped++; } } } return(queryResult); }
ComplexQueryResult OrNotQuery(int[] tag1Ids, int[] tag2Ids, int [] allTagIds, int pageSize, int skip, CLR.HashSet <string> tagsToExclude = null) { var queryResult = new ComplexQueryResult { Results = new List <Question>(pageSize), BaseQueryCounter = 0, ItemsSkipped = 0, ExcludedCounter = 0 }; // TODO this has a small bug, we can get items out of order as we pull them thru in pairs // if t2 has several items that are larger than t1, t1 will still come out first!! // So algorithm needs to be: // 1) pull the LARGEST value (from t1 or t2) // 2) process this item // 3) repeat 1) again var orNotHashSet = cache.Value.GetCachedHashSet(tag2Ids); var seenBefore = secondCache.Value.GetCachedHashSet(); using (IEnumerator <int> e1 = tag1Ids.AsEnumerable().GetEnumerator()) using (IEnumerator <int> e2 = allTagIds.AsEnumerable().GetEnumerator()) { while (e1.MoveNext() && e2.MoveNext()) { if (queryResult.Results.Count >= pageSize) { break; } queryResult.BaseQueryCounter++; if (tagsToExclude != null && questions[e1.Current].Tags.Any(t => tagsToExclude.Contains(t))) { queryResult.ExcludedCounter++; } else if (orNotHashSet.Contains(e1.Current) == false && seenBefore.Add(e1.Current)) { if (queryResult.ItemsSkipped >= skip) { queryResult.Results.Add(questions[e1.Current]); } else { queryResult.ItemsSkipped++; } } if (queryResult.Results.Count >= pageSize) { break; } // TODO should we be doing this here as well!!?!?! //baseQueryCounter++; if (tagsToExclude != null && questions[e2.Current].Tags.Any(t => tagsToExclude.Contains(t))) { queryResult.ExcludedCounter++; } else if (orNotHashSet.Contains(e2.Current) == false && seenBefore.Add(e2.Current)) { if (queryResult.ItemsSkipped >= skip) { queryResult.Results.Add(questions[e2.Current]); } else { queryResult.ItemsSkipped++; } } } } return(queryResult); }