public static ReqlAst ToReqlAst(object val, Func<object, ReqlAst> hook) { return ToReqlAst(val, 100, hook); }
private static ReqlAst ToReqlAst(object val, int remainingDepth, Func<object, ReqlAst> hook = null ) { if( remainingDepth <= 0 ) { throw new ReqlDriverCompileError("Recursion limit reached converting to ReqlAst"); } if( hook != null ) { var converted = hook(val); if( !ReferenceEquals(converted, null) ) { return converted; } } var ast = val as ReqlAst; if( !ReferenceEquals(ast, null) ) { return ast; } var token = val as JToken; if( token != null ) { return new Poco(token); } var lst = val as IList; if( lst != null ) { Arguments innerValues = new Arguments(); foreach( object innerValue in lst ) { innerValues.Add(ToReqlAst(innerValue, remainingDepth - 1)); } return new MakeArray(innerValues, null); } var dict = val as IDictionary; if( dict != null ) { var obj = new Dictionary<string, ReqlAst>(); foreach( var keyObj in dict.Keys ) { var key = keyObj as string; if( key == null ) { throw new ReqlDriverCompileError("Object keys can only be strings"); } obj[key] = ToReqlAst(dict[keyObj]); } return MakeObj.fromMap(obj); } var del = val as Delegate; if( del != null ) { return Func.FromLambda(del); } var dt = val as DateTime?; if (dt != null) { return new Poco(dt); } var dto = val as DateTimeOffset?; if (dto != null) { return new Poco(dto); } var @int = val as int?; if( @int != null ) { return new Datum(@int); } if( IsNumber(val) ) { return new Datum(val); } var @bool = val as bool?; if( @bool != null ) { return new Datum(@bool); } var str = val as string; if( str != null ) { return new Datum(str); } if( val == null ) { return new Datum(null); } return new Poco(val); }
public async Task<ReqlExpr> AsCountTableQueryAsync(RethinkDB rdb, Table table, string requesterId, string feedOwnerId, CancellationToken cancellationToken = default(CancellationToken)) { // Make sure we have all the data we need. await this.resolveDependenciesRunner.RunOnce(cancellationToken); // Find the name of the index to use. var index = this.TableIndex(); // Find the date boundary values. var lowerDateBound = this.boundaries?.TryGetValue(TentFeedRequestBoundaryType.Since)?.Date ?? this.boundaries?.TryGetValue(TentFeedRequestBoundaryType.Until)?.Date; var upperDateBound = this.boundaries?.TryGetValue(TentFeedRequestBoundaryType.Before)?.Date; // Filter by owner and date. var query = (ReqlExpr)table.Between( new object[] { feedOwnerId, lowerDateBound != null ? rdb.Expr(lowerDateBound) : rdb.Minval() }, new object[] { feedOwnerId, upperDateBound != null ? rdb.Expr(upperDateBound) : rdb.Maxval() })[new { index, left_bound = "open", right_bound = "open" }]; // Set the order-by depending on the boundary type. query = query.OrderBy()[new { index = this.boundaries != null && this.boundaries.ContainsKey(TentFeedRequestBoundaryType.Since) ? (object)rdb.Asc(index) : (object)rdb.Desc(index) }]; var filters = new List<Func<ReqlExpr, ReqlExpr>>(); // Entities. if (this.specialEntities == TentFeedRequestSpecialEntities.Followings) filters.Add(r => r.G("is_from_following").Eq(true)); else if (this.users != null && this.users.Any()) filters.Add(r => rdb.BetterOr(this.users.Select(u => r.G("user").Eq(u.Id)).Cast<object>().ToArray())); // Post type filter. if (this.types != null && this.types.Any()) { // Condition on a single type. var typeCondition = new Func<ReqlExpr, ITentPostType, ReqlExpr>((r, type) => type.WildCard ? (ReqlExpr)r.G("type").Match($"^{Regex.Escape(type.Type)}#") : r.G("type").Eq(type.ToString())); // Combine the type conditions as part of an OR expression. filters.Add(r => rdb.BetterOr(this.types.Select(type => typeCondition(r, type)).Cast<object>().ToArray())); } // Condition on a single mention. var mentionCondition = new Func<ReqlExpr, ITentRequestPost, ReqlExpr>((r, mention) => r.G("mentions") // Map each mention for the current row to a boolean. .Map(m => mention.Post == null ? m.G("user").Eq(mention.User.Id) : rdb.BetterAnd(m.G("user").Eq(mention.User.Id), m.G("post").Eq(mention.Post.Id))) // Reduce the resulting booleans to just one (any). .Reduce((b1, b2) => rdb.BetterOr(b1, b2)) .Default_(false)); // Mentions. if (this.mentions != null && this.mentions.Any()) { // Combine the mention conditions, first by AND, then by OR. filters.Add(r => rdb.BetterAnd(this.mentions .Select(andMentions => rdb.BetterOr(andMentions.Select(mention => mentionCondition(r, mention)).Cast<object>().ToArray())) .Cast<object>().ToArray())); } // Not mentions. if (this.notMentions != null && this.notMentions.Any()) { // Combine the not mention conditions, first by AND, then by OR. filters.Add(r => rdb.BetterAnd(this.notMentions .Select(andNotMentions => rdb.BetterOr(andNotMentions.Select(notMention => mentionCondition(r, notMention).Not()).Cast<object>().ToArray())) .Cast<object>().ToArray())); } // Permissions. if (requesterId != feedOwnerId) { filters.Add(r => rdb.BetterAnd( r.G("user").Eq(feedOwnerId), rdb.BetterOr( r.G("permissions").G("public").Eq(true), r.G("permissions").G("users").Contains(requesterId)))); } // Apply all the filters as part of an AND expression. if (filters.Any()) query = query.Filter(r => rdb.BetterAnd(filters.Select(f => f(r)).Cast<object>().ToArray())); return query; }