using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json.Linq; using RethinkDb.Driver.Model; using RethinkDb.Driver.Net; using RethinkDb.Driver.Proto; using RethinkDb.Driver.Utils; namespace RethinkDb.Driver.Ast { /// /// Base class for all reql queries. /// public class ReqlAst { #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member protected internal TermType TermType { get; } protected internal Arguments Args { get; } protected internal OptArgs OptArgs { get; } protected internal ReqlAst(TermType termType, Arguments args, OptArgs optargs) { this.TermType = termType; this.Args = args ?? new Arguments(); this.OptArgs = optargs ?? new OptArgs(); } protected internal virtual object Build() { // Create a JSON object from the Ast JArray list = new JArray(); list.Add(TermType); if( Args.Count > 0 ) { var collect = Args.Select(a => { return a.Build(); }); list.Add(new JArray(collect)); } else { list.Add(new JArray()); } if( OptArgs.Count > 0 ) { list.Add(BuildOptarg(this.OptArgs)); } return list; } protected internal static JObject BuildOptarg(OptArgs opts) { var dict = opts.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Build()); return JObject.FromObject(dict); } #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member #region DYNAMIC LANGUAGE RUNTIME (DLR) RUNNERS /// /// Runs the query on the connection. If you know the response type /// of your query, T (SUCCESS_ATOM) or Cursor[T] (SUCCESS_SEQUENCE or SUCCESS_PARTIAL) /// it's recommended to use `.RunAtom`, `.RunCursor` or `.RunResult` helpers /// as they offer a slight edge in performance since both bypass the /// dynamic language runtime execution engine. /// /// Returns T or Cursor[T] public virtual Task RunAsync(IConnection conn, object runOpts = null, CancellationToken cancelToken = default) { return conn.RunAsync(this, runOpts, cancelToken); } /// /// Runs the query on the connection. If you know the response type /// of your query, T (SUCCESS_ATOM) or Cursor[T] (SUCCESS_SEQUENCE or SUCCESS_PARTIAL) /// it's recommended to use `.RunAtom`, `.RunCursor` or `.RunResult` helpers /// as they offer a slight edge in performance since both bypass the /// dynamic language runtime execution engine. /// /// Returns T or Cursor[T] public virtual Task RunAsync(IConnection conn, CancellationToken cancelToken) { return RunAsync(conn, null, cancelToken); } /// /// Runs the query on the connection. If you know the response type /// of your query, T (SUCCESS_ATOM) or Cursor[T] (SUCCESS_SEQUENCE or SUCCESS_PARTIAL) /// it's recommended to use `.RunAtom`, `.RunCursor` or `.RunResult` helpers /// as they offer a slight edge in performance since both bypass the /// dynamic language runtime execution engine. /// /// Returns T or Cursor[T] /// /// connection /// global anonymous type optional arguments /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task RunAsync(IConnection conn, object runOpts = null, CancellationToken cancelToken = default) { return RunAsync(conn, runOpts, cancelToken); } /// /// Runs the query on the connection. If you know the response type /// of your query, T (SUCCESS_ATOM) or Cursor[T] (SUCCESS_SEQUENCE or SUCCESS_PARTIAL) /// it's recommended to use `.RunAtom`, `.RunCursor` or `.RunResult` helpers /// as they offer a slight edge in performance since both bypass the /// dynamic language runtime execution engine. /// /// Returns T or Cursor[T] /// /// connection /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task RunAsync(IConnection conn, CancellationToken cancelToken) { return RunAsync(conn, null, cancelToken); } /// /// Runs the query on the connection. If you know the response type /// of your query, T (SUCCESS_ATOM) or Cursor[T] (SUCCESS_SEQUENCE or SUCCESS_PARTIAL) /// it's recommended to use `.RunAtom`, `.RunCursor` or `.RunResult` helpers /// as they offer a slight edge in performance since both bypass the /// dynamic language runtime execution engine. /// /// Returns T or Cursor[T] public virtual dynamic Run(IConnection conn, object runOpts = null) { return RunAsync(conn, runOpts).WaitSync(); } /// /// Runs the query on the connection. If you know the response type /// of your query, T (SUCCESS_ATOM) or Cursor[T] (SUCCESS_SEQUENCE or SUCCESS_PARTIAL) /// it's recommended to use `.RunAtom`, `.RunCursor` or `.RunResult` helpers /// as they offer a slight edge in performance since both bypass the /// dynamic language runtime execution engine. /// /// Returns T or Cursor[T] public virtual dynamic Run(IConnection conn, object runOpts = null) { return Run(conn, runOpts); } #endregion #region RESPONSE TYPED RUNNERS /// /// Executes a query with no expected response. Useful for fire-and-forget queries like insert, update. /// public void RunNoReply(IConnection conn, object runOpts = null) { conn.RunNoReply(this, runOpts); } /// /// Use this method if you're expecting a cursor (SUCCESS_SEQUENCE or SUCCESS_PARTIAL) response /// from your query. This method offers a slight edge in performance without the need for the /// dynamic language runtime like the run() method uses. /// /// /// connection /// global anonymous type optional arguments /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. /// A Cursor public virtual Task> RunCursorAsync(IConnection conn, object runOpts = null, CancellationToken cancelToken = default) { return conn.RunCursorAsync(this, runOpts, cancelToken); } /// /// Use this method if you're expecting a cursor (SUCCESS_SEQUENCE or SUCCESS_PARTIAL) response /// from your query. This method offers a slight edge in performance without the need for the /// dynamic language runtime like the run() method uses. /// /// /// connection /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. /// A Cursor public virtual Task> RunCursorAsync(IConnection conn, CancellationToken cancelToken) { return RunCursorAsync(conn, null, cancelToken); } /// /// Use this method if you're expecting a cursor (SUCCESS_SEQUENCE or SUCCESS_PARTIAL) response /// from your query. This method offers a slight edge in performance without the need for the /// dynamic language runtime like the run() method uses. /// /// /// connection /// global anonymous type optional arguments /// A Cursor public virtual Cursor RunCursor(IConnection conn, object runOpts = null) { return RunCursorAsync(conn, runOpts).WaitSync(); } /// /// Use this method if you're expecting SUCCESS_ATOM response from your query. This /// method offers a slight edge in performance without the need for the /// dynamic language runtime like the run() method uses. /// /// connection /// global anonymous type optional arguments /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task RunAtomAsync(IConnection conn, object runOpts = null, CancellationToken cancelToken = default) { return conn.RunAtomAsync(this, runOpts, cancelToken); } /// /// Use this method if you're expecting SUCCESS_ATOM response from your query. This /// method offers a slight edge in performance without the need for the /// dynamic language runtime like the run() method uses. /// /// connection /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task RunAtomAsync(IConnection conn, CancellationToken cancelToken) { return RunAtomAsync(conn, null, cancelToken); } /// /// Use this method if you're expecting SUCCESS_ATOM response from your query. This /// method offers a slight edge in performance without the need for the /// dynamic language runtime like the run() method uses. /// /// connection /// global anonymous type optional arguments public virtual T RunAtom(IConnection conn, object runOpts = null) { return RunAtomAsync(conn, runOpts).WaitSync(); } /// /// Use this method if you're expecting SUCCESS_ATOM or SUCCESS_SEQUENCE response from your query. This /// method offers a slight edge in performance without the need for the /// dynamic language runtime like the run() method uses. Consider using RunAtom or RunCursor if your /// response is either SUCCESS_ATOM or SUCCESS_SEQUENCE respectively. Exercise caution using this method /// with large datasets as the server can switch responses from SUCESS_SEQUENCE to SUCCESS_PARTIAL for the /// same exact query. Refer to the online documentation for this run helper. /// /// connection /// global anonymous type optional arguments /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task RunResultAsync(IConnection conn, object runOpts = null, CancellationToken cancelToken = default) { return conn.RunResultAsync(this, runOpts, cancelToken); } /// /// Use this method if you're expecting SUCCESS_ATOM or SUCCESS_SEQUENCE response from your query. This /// method offers a slight edge in performance without the need for the /// dynamic language runtime like the run() method uses. Consider using RunAtom or RunCursor if your /// response is either SUCCESS_ATOM or SUCCESS_SEQUENCE respectively. Exercise caution using this method /// with large datasets as the server can switch responses from SUCESS_SEQUENCE to SUCCESS_PARTIAL for the /// same exact query. Refer to the online documentation for this run helper. /// /// connection /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task RunResultAsync(IConnection conn, CancellationToken cancelToken) { return RunResultAsync(conn, null, cancelToken); } /// /// Use this method if you're expecting SUCCESS_ATOM or SUCCESS_SEQUENCE response from your query. This /// method offers a slight edge in performance without the need for the /// dynamic language runtime like the run() method uses. Consider using RunAtom or RunCursor if your /// response is either SUCCESS_ATOM or SUCCESS_SEQUENCE respectively. Exercise caution using this method /// with large datasets as the server can switch responses from SUCESS_SEQUENCE to SUCCESS_PARTIAL for the /// same exact query. Refer to the online documentation for this run helper. /// /// connection /// global anonymous type optional arguments public virtual T RunResult(IConnection conn, object runOpts = null) { return RunResultAsync(conn, runOpts).WaitSync(); } #endregion #region EXTRA RUN HELPERS /// /// OBSOLETE: Please use the .RunWriteAsync() method instead. /// [Obsolete("The .RunResultAsync() method has been renamed to .RunWriteAsync(). Please use the new method name instead.", error: false)] public virtual Task RunResultAsync(IConnection conn, object runOpts = null, CancellationToken cancelToken = default) { return RunWriteAsync(conn, runOpts, cancelToken); } /// /// OBSOLETE: Please use .RunWriteAsync() method instead. /// [Obsolete("The .RunResultAsync() method has been renamed to .RunWriteAsync(). Please use the new method name instead.", error: false)] public virtual Task RunResultAsync(IConnection conn, CancellationToken cancelToken) { return RunWriteAsync(conn, null, cancelToken); } /// /// OBSOLETE: Please use .RunWrite() method instead. /// [Obsolete("The .RunResult() method has been renamed to .RunWrite(). Please use the new method name instead.", error: false)] public virtual Result RunResult(IConnection conn, object runOpts = null) { return RunWriteAsync(conn, runOpts).WaitSync(); } /// /// Helper shortcut for DML type of queries that returns # of inserts, deletes, errors. /// This method bypasses the dynamic language runtime for extra performance. /// /// connection /// global anonymous type optional arguments /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task RunWriteAsync(IConnection conn, object runOpts = null, CancellationToken cancelToken = default) { return conn.RunAtomAsync(this, runOpts, cancelToken); } /// /// Helper shortcut for DML type of queries that returns # of inserts, deletes, errors. /// This method bypasses the dynamic language runtime for extra performance. /// /// connection /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task RunWriteAsync(IConnection conn, CancellationToken cancelToken) { return RunWriteAsync(conn, null, cancelToken); } /// /// Helper shortcut for DML type of queries that returns # of inserts, deletes, errors. /// This method bypasses the dynamic language runtime for extra performance. /// /// connection /// global anonymous type optional arguments public virtual Result RunWrite(IConnection conn, object runOpts = null) { return RunWriteAsync(conn, runOpts).WaitSync(); } /// /// Runs a query on the server and returns the raw object in an unsafe way /// with minimal client-side processing. The unbridled use of this method can /// lead to memory leaks on both the client and server. This method should only /// be used in well-understood and advanced scenarios. /// /// The connection object /// global anonymous type optional arguments /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task RunUnsafeAsync(IConnection conn, object runOpts = null, CancellationToken cancelToken = default) { return conn.RunUnsafeAsync(this, runOpts, cancelToken); } /// /// Helper shortcut for change feeds, use if your query is expecting an infinite changes() stream. /// This method bypasses the dynamic language runtime for extra performance. /// /// The document type of new/old value /// connection /// global anonymous type optional arguments /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task>> RunChangesAsync(IConnection conn, object runOpts = null, CancellationToken cancelToken = default) { return conn.RunCursorAsync>(this, runOpts, cancelToken); } /// /// Helper shortcut for change feeds, use if your query is expecting an infinite changes() stream. /// This method bypasses the dynamic language runtime for extra performance. /// /// The document type of new/old value /// connection /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task>> RunChangesAsync(IConnection conn, CancellationToken cancelToken) { return RunChangesAsync(conn, null, cancelToken); } /// /// Helper shortcut for change feeds, use if your query is expecting an infinite changes() stream. /// This method bypasses the dynamic language runtime for extra performance. /// /// The document type of new/old value /// connection /// global anonymous type optional arguments public virtual Cursor> RunChanges(IConnection conn, object runOpts = null) { return RunChangesAsync(conn, runOpts).WaitSync(); } #endregion /// /// Helper shortcut for grouping queries. /// This method bypasses the dynamic language runtime for extra performance. /// /// The key type of how items are grouped /// The type of items /// connection /// global anonymous type optional arguments /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual async Task>> RunGroupingAsync(IConnection conn, object runOpts = null, CancellationToken cancelToken = default) { var tsk = await RunAtomAsync>(conn, runOpts, cancelToken).ConfigureAwait(false); return tsk; } /// /// Helper shortcut for grouping queries. /// This method bypasses the dynamic language runtime for extra performance. /// /// The key type of how items are grouped /// The type of items /// connection /// Cancellation token used to stop *waiting* for a query response. The cancellation token does not cancel the query's execution on the server. public virtual Task>> RunGroupingAsync(IConnection conn, CancellationToken cancelToken) { return RunGroupingAsync(conn, null, cancelToken); } /// /// Helper shortcut for grouping queries. /// This method bypasses the dynamic language runtime for extra performance. /// /// The key type of how items are grouped /// The type of items /// connection /// global anonymous type optional arguments public virtual IEnumerable> RunGrouping(IConnection conn, object runOpts = null) { return RunAtomAsync>(conn, runOpts).WaitSync(); } } }