/// <summary> /// A special intermediate function for converting string chaining into real chaining. /// </summary> /// <param name="chainDataString"></param> /// <param name="search"></param> /// <param name="previousChains"></param> /// <typeparam name="S"></typeparam> /// <typeparam name="V"></typeparam> /// <returns></returns> protected Task ChainStringAsync <S, V>(ChainRequestString chainDataString, Func <S, Task <List <V> > > search, List <List <IIdView> > previousChains) where S : IConstrainedSearcher where V : IIdView { var t = timer.StartTimer($"{chainDataString.endpoint} {string.Join(".", chainDataString.chains)}"); try { var chainData = new ChainRequest <S, V>(chainDataString) { retriever = search }; try { chainData.baseSearch = JsonSerializer.Deserialize <S>(chainDataString.search, config.JsonOptions); } catch (Exception ex) { //I don't care too much about json deseralize errors, just the message. I don't even log it. throw new BadRequestException(ex.Message + " (CHAIN REMINDER: json search comes last AFTER all . chaining in a request)"); } return(ChainAsync(chainData, previousChains)); } finally { timer.EndTimer(t); } }
/// <summary> /// THE REAL PROPER CHAINING ENDPOINT! Will perform ONE chain request (after linking with previous chains) /// </summary> /// <param name="data"></param> /// <param name="baggage"></param> /// <typeparam name="S"></typeparam> /// <typeparam name="V"></typeparam> /// <returns></returns> public async Task ChainAsync <S, V>(ChainRequest <S, V> data, List <List <IIdView> > previousChains) where V : IIdView where S : IConstrainedSearcher { Dictionary <string, PropertyInfo> properties = null; Type type = typeof(V); //My poor design has led to this... if (type == typeof(UserViewFull)) { type = typeof(UserViewBasic); } var baseProperties = GetProperties(type); //Before doing ANYTHING, IMMEDIATELY convert fields to actual properties. It's easy if they pass us null: they want everything. if (data.fields == null) { properties = baseProperties.ToDictionary(x => x.Name, x => x); } else { var lowerFields = data.fields.Select(x => x.ToLower()); properties = baseProperties.Where(x => lowerFields.Contains(x.Name.ToLower())).ToDictionary(x => x.Name, x => x); if (properties.Count != data.fields.Count) { throw new BadRequestException($"Unknown fields in list: {string.Join(",", data.fields)}"); } } //Parse the chains, get the ids. WARN: THIS IS DESTRUCTIVE TO DATA.BASESEARCH!!! foreach (var c in data.chains) { LinkToSearch(c, previousChains, data.baseSearch); } var myResults = await data.retriever(data.baseSearch); previousChains.Add(myResults.Cast <IIdView>().ToList()); //Only add ones that aren't in the list foreach (var v in myResults) { if (!data.mergeList.Any(x => x.id == v.id)) { var result = new TaggedChainResult() { id = v.id, result = new ExpandoObject() }; foreach (var p in properties) { result.result.TryAdd(p.Key, p.Value.GetValue(v)); } lock (data.mergeLock) { data.mergeList.Add(result); } } } }