using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using RethinkDb.Driver.Model; using RethinkDb.Driver.Proto; namespace RethinkDb.Driver.Ast { /// /// Used to inject raw protocol strings when the AST is dumped on the wire. /// public class ReqlRawExpr : ReqlExpr { private string RawProtocol { get; } /// /// Create an AST mid-flight with the raw protocol string. /// /// Raw protocol string from ReqlAst.Build() internal ReqlRawExpr(string rawProtocol) : base(new TermType(), null, null) { this.RawProtocol = rawProtocol; } /// /// Return the JToken representation of the raw protocol /// protected internal override object Build() { return JToken.Parse(this.RawProtocol); } } /// /// Used to inject raw protocol strings when the AST is dumped on the wire. /// public class ReqlRaw : ReqlAst { private string RawProtocol { get; } /// /// Create an AST mid-flight with the raw protocol string. /// /// Raw protocol string from ReqlAst.Build() internal ReqlRaw(string rawProtocol) : base(new TermType(), null, null) { this.RawProtocol = rawProtocol; } /// /// Return the JToken representation of the raw protocol /// protected internal override object Build() { return JToken.Parse(this.RawProtocol); } private const string RawTokenType = "$reql_reqlraw$"; /// /// Convert an AST item into a raw protocol string representation. /// Useful for serialization. /// /// Can be anything, ReqlFunction or otherwise public static string ToRawString(object astItem) { var list = new List(); var token = Util.ToReqlAst(astItem, o => HookFuncTypes(o, list)).Build() as JToken; var query = token.ToString(Formatting.None); //pack return $"{string.Join("|", list)}{RawTokenType}{query}"; } internal static string HydrateProtocolString(string reqlRawString) { var tokenLocation = reqlRawString.IndexOf(RawTokenType, StringComparison.Ordinal); var guidStrings = reqlRawString.Substring(0, tokenLocation); var query = reqlRawString.Substring(tokenLocation + RawTokenType.Length); //unpack var replaceTokens = guidStrings.Split('|') .Select(g => new { GuidString = $@"""{g}""", VarId = Func.NextVarId() }); foreach (var token in replaceTokens) { query = query.Replace(token.GuidString, token.VarId.ToString()); } return query; } /// /// Convert a raw protocol string into an AST term that will /// be injected when the AST is serialized. /// /// The raw protocol string to inject /// A raw AST term public static ReqlRaw FromRawString(string reqlRawString) { var query = HydrateProtocolString(reqlRawString); return new ReqlRaw(query); } private static ReqlAst HookFuncTypes(object val, List context) { var del = val as Delegate; if( del != null ) { return Func.Serialize(del, context); } return null; } } }