////////////////////////////////////////////////////////////////////////////////
//                            THE HIGH-LEVEL VIEW                             //
////////////////////////////////////////////////////////////////////////////////

// Process: When you first open a connection, send the magic number
// for the version of the protobuf you're targetting (in the [Version]
// enum).  This should **NOT** be sent as a protobuf; just send the
// little-endian 32-bit integer over the wire raw.  This number should
// only be sent once per connection.

// The magic number shall be followed by an authorization key.  The
// first 4 bytes are the length of the key to be sent as a little-endian
// 32-bit integer, followed by the key string.  Even if there is no key,
// an empty string should be sent (length 0 and no data).  The server will
// then respond with a NULL-terminated string response.  "SUCCESS" indicates
// that the connection has been accepted. Any other response indicates an
// error, and the response string should describe the error.

// Next, for each query you want to send, construct a [Query] protobuf
// and serialize it to a binary blob.  Send the blob's size to the
// server encoded as a little-endian 32-bit integer, followed by the
// blob itself.  You will recieve a [Response] protobuf back preceded
// by its own size, once again encoded as a little-endian 32-bit
// integer.  You can see an example exchange below in **EXAMPLE**.

// A query consists of a [Term] to evaluate and a unique-per-connection
// [token].

// Tokens are used for two things:
// * Keeping track of which responses correspond to which queries.
// * Batched queries.  Some queries return lots of results, so we send back
//   batches of <1000, and you need to send a [CONTINUE] query with the same
//   token to get more results from the original query.
////////////////////////////////////////////////////////////////////////////////

// This enum contains the magic numbers for your version.  See **THE HIGH-LEVEL
// VIEW** for what to do with it.
message VersionDummy { // We need to wrap it like this for some
                       // non-conforming protobuf libraries
    enum Version {
        V0_1 = 0x3f61ba36;
        V0_2 = 0x723081e1;
    }
}

// You send one of:
// * A [START] query with a [Term] to evaluate and a unique-per-connection token.
// * A [CONTINUE] query with the same token as a [START] query that returned
//   [SUCCESS_PARTIAL] in its [Response].
// * A [STOP] query with the same token as a [START] query that you want to stop.
// * A [NOREPLY_WAIT] query with a unique per-connection token. The server answers
//   with a [WAIT_COMPLETE] [Response].
message Query {
    enum QueryType {
        START    = 1; // Start a new query.
        CONTINUE = 2; // Continue a query that returned [SUCCESS_PARTIAL]
                      // (see [Response]).
        STOP     = 3; // Stop a query partway through executing.
        NOREPLY_WAIT = 4;
                      // Wait for noreply operations to finish.
    }
    optional QueryType type = 1;
    // A [Term] is how we represent the operations we want a query to perform.
    optional Term query = 2; // only present when [type] = [START]
    optional int64 token = 3;
    // This flag is ignored on the server.  `noreply` should be added
    // to `global_optargs` instead (the key "noreply" should map to
    // either true or false).
    optional bool OBSOLETE_noreply = 4 [default = false];

    // If this is set to [true], then [Datum] values will sometimes be
    // of [DatumType] [R_JSON] (see below).  This can provide enormous
    // speedups in languages with poor protobuf libraries.
    optional bool accepts_r_json = 5 [default = false];

    message AssocPair {
        optional string key = 1;
        optional Term val = 2;
    }
    repeated AssocPair global_optargs = 6;
}

// A backtrace frame (see `backtrace` in Response below)
message Frame {
    enum FrameType {
        POS = 1; // Error occured in a positional argument.
        OPT = 2; // Error occured in an optional argument.
    }
    optional FrameType type = 1;
    optional int64 pos = 2; // The index of the positional argument.
    optional string opt = 3; // The name of the optional argument.
}
message Backtrace {
    repeated Frame frames = 1;
}

// You get back a response with the same [token] as your query.
message Response {
    enum ResponseType {
        // These response types indicate success.
        SUCCESS_ATOM     = 1; // Query returned a single RQL datatype.
        SUCCESS_SEQUENCE = 2; // Query returned a sequence of RQL datatypes.
        SUCCESS_PARTIAL  = 3; // Query returned a partial sequence of RQL
                              // datatypes.  If you send a [CONTINUE] query with
                              // the same token as this response, you will get
                              // more of the sequence.  Keep sending [CONTINUE]
                              // queries until you get back [SUCCESS_SEQUENCE].
        WAIT_COMPLETE    = 4; // A [NOREPLY_WAIT] query completed.

        // These response types indicate failure.
        CLIENT_ERROR  = 16; // Means the client is buggy.  An example is if the
                            // client sends a malformed protobuf, or tries to
                            // send [CONTINUE] for an unknown token.
        COMPILE_ERROR = 17; // Means the query failed during parsing or type
                            // checking.  For example, if you pass too many
                            // arguments to a function.
        RUNTIME_ERROR = 18; // Means the query failed at runtime.  An example is
                            // if you add together two values from a table, but
                            // they turn out at runtime to be booleans rather
                            // than numbers.
    }
    optional ResponseType type = 1;
    optional int64 token = 2; // Indicates what [Query] this response corresponds to.

    // [response] contains 1 RQL datum if [type] is [SUCCESS_ATOM], or many RQL
    // data if [type] is [SUCCESS_SEQUENCE] or [SUCCESS_PARTIAL].  It contains 1
    // error message (of type [R_STR]) in all other cases.
    repeated Datum response = 3;

    // If [type] is [CLIENT_ERROR], [TYPE_ERROR], or [RUNTIME_ERROR], then a
    // backtrace will be provided.  The backtrace says where in the query the
    // error occured.  Ideally this information will be presented to the user as
    // a pretty-printed version of their query with the erroneous section
    // underlined.  A backtrace is a series of 0 or more [Frame]s, each of which
    // specifies either the index of a positional argument or the name of an
    // optional argument.  (Those words will make more sense if you look at the
    // [Term] message below.)
    optional Backtrace backtrace = 4; // Contains n [Frame]s when you get back an error.

    // If the [global_optargs] in the [Query] that this [Response] is a
    // response to contains a key "profile" which maps to a static value of
    // true then [profile] will contain a [Datum] which provides profiling
    // information about the execution of the query. This field should be
    // returned to the user along with the result that would normally be
    // returned (a datum or a cursor). In official drivers this is accomplished
    // by putting them inside of an object with "value" mapping to the return
    // value and "profile" mapping to the profile object.
    optional Datum profile = 5;
}

// A [Datum] is a chunk of data that can be serialized to disk or returned to
// the user in a Response.  Currently we only support JSON types, but we may
// support other types in the future (e.g., a date type or an integer type).
message Datum {
    enum DatumType {
        R_NULL   = 1;
        R_BOOL   = 2;
        R_NUM    = 3; // a double
        R_STR    = 4;
        R_ARRAY  = 5;
        R_OBJECT = 6;
        // This [DatumType] will only be used if [accepts_r_json] is
        // set to [true] in [Query].  [r_str] will be filled with a
        // JSON encoding of the [Datum].
        R_JSON   = 7; // uses r_str
    }
    optional DatumType type = 1;
    optional bool r_bool = 2;
    optional double r_num = 3;
    optional string r_str = 4;

    repeated Datum r_array = 5;
    message AssocPair {
        optional string key = 1;
        optional Datum val = 2;
    }
    repeated AssocPair r_object = 6;

    extensions 10000 to 20000;
}

// A [Term] is either a piece of data (see **Datum** above), or an operator and
// its operands.  If you have a [Datum], it's stored in the member [datum].  If
// you have an operator, its positional arguments are stored in [args] and its
// optional arguments are stored in [optargs].
//
// A note about type signatures:
// We use the following notation to denote types:
//   arg1_type, arg2_type, argrest_type... -> result_type
// So, for example, if we have a function `avg` that takes any number of
// arguments and averages them, we might write:
//   NUMBER... -> NUMBER
// Or if we had a function that took one number modulo another:
//   NUMBER, NUMBER -> NUMBER
// Or a function that takes a table and a primary key of any Datum type, then
// retrieves the entry with that primary key:
//   Table, DATUM -> OBJECT
// Some arguments must be provided as literal values (and not the results of sub
// terms).  These are marked with a `!`.
// Optional arguments are specified within curly braces as argname `:` value
// type (e.x `{use_outdated:BOOL}`)
// Many RQL operations are polymorphic. For these, alterantive type signatures
// are separated by `|`.
//
// The RQL type hierarchy is as follows:
//   Top
//     DATUM
//       NULL
//       BOOL
//       NUMBER
//       STRING
//       OBJECT
//         SingleSelection
//       ARRAY
//     Sequence
//       ARRAY
//       Stream
//         StreamSelection
//           Table
//     Database
//     Function
//     Ordering - used only by ORDER_BY
//     Pathspec -- an object, string, or array that specifies a path
//   Error
message Term {
    enum TermType {
        // A RQL datum, stored in `datum` below.
        DATUM = 1;

        MAKE_ARRAY = 2; // DATUM... -> ARRAY
        // Evaluate the terms in [optargs] and make an object
        MAKE_OBJ   = 3; // {...} -> OBJECT

        // * Compound types

        // Takes an integer representing a variable and returns the value stored
        // in that variable.  It's the responsibility of the client to translate
        // from their local representation of a variable to a unique _non-negative_
        // integer for that variable.  (We do it this way instead of letting
        // clients provide variable names as strings to discourage
        // variable-capturing client libraries, and because it's more efficient
        // on the wire.)
        VAR          = 10; // !NUMBER -> DATUM
        // Takes some javascript code and executes it.
        JAVASCRIPT   = 11; // STRING {timeout: !NUMBER} -> DATUM |
                           // STRING {timeout: !NUMBER} -> Function(*)

        // Takes a string and throws an error with that message.
        // Inside of a `default` block, you can omit the first
        // argument to rethrow whatever error you catch (this is most
        // useful as an argument to the `default` filter optarg).
        ERROR        = 12; // STRING -> Error | -> Error
        // Takes nothing and returns a reference to the implicit variable.
        IMPLICIT_VAR = 13; // -> DATUM

        // * Data Operators
        // Returns a reference to a database.
        DB    = 14; // STRING -> Database
        // Returns a reference to a table.
        TABLE = 15; // Database, STRING, {use_outdated:BOOL} -> Table | STRING, {use_outdated:BOOL} -> Table
        // Gets a single element from a table by its primary or a secondary key.
        GET   = 16; // Table, STRING -> SingleSelection | Table, NUMBER -> SingleSelection |
                    // Table, STRING -> NULL            | Table, NUMBER -> NULL |
        GET_ALL = 78; // Table, DATUM..., {index:!STRING} => ARRAY

        // Simple DATUM Ops
        EQ  = 17; // DATUM... -> BOOL
        NE  = 18; // DATUM... -> BOOL
        LT  = 19; // DATUM... -> BOOL
        LE  = 20; // DATUM... -> BOOL
        GT  = 21; // DATUM... -> BOOL
        GE  = 22; // DATUM... -> BOOL
        NOT = 23; // BOOL -> BOOL
        // ADD can either add two numbers or concatenate two arrays.
        ADD = 24; // NUMBER... -> NUMBER | STRING... -> STRING
        SUB = 25; // NUMBER... -> NUMBER
        MUL = 26; // NUMBER... -> NUMBER
        DIV = 27; // NUMBER... -> NUMBER
        MOD = 28; // NUMBER, NUMBER -> NUMBER

        // DATUM Array Ops
        // Append a single element to the end of an array (like `snoc`).
        APPEND = 29; // ARRAY, DATUM -> ARRAY
        // Prepend a single element to the end of an array (like `cons`).
        PREPEND = 80; // ARRAY, DATUM -> ARRAY
        //Remove the elements of one array from another array.
        DIFFERENCE = 95; // ARRAY, ARRAY -> ARRAY

        // DATUM Set Ops
        // Set ops work on arrays. They don't use actual sets and thus have
        // performance characteristics you would expect from arrays rather than
        // from sets. All set operations have the post condition that they
        // array they return contains no duplicate values.
        SET_INSERT = 88; // ARRAY, DATUM -> ARRAY
        SET_INTERSECTION = 89; // ARRAY, ARRAY -> ARRAY
        SET_UNION = 90; // ARRAY, ARRAY -> ARRAY
        SET_DIFFERENCE = 91; // ARRAY, ARRAY -> ARRAY

        SLICE  = 30; // Sequence, NUMBER, NUMBER -> Sequence
        SKIP  = 70; // Sequence, NUMBER -> Sequence
        LIMIT = 71; // Sequence, NUMBER -> Sequence
        INDEXES_OF = 87; // Sequence, DATUM -> Sequence | Sequence, Function(1) -> Sequence
        CONTAINS = 93; // Sequence, DATUM -> BOOL | Sequence, Function(1) -> BOOL

        // Stream/Object Ops
        // Get a particular field from an object, or map that over a
        // sequence.
        GET_FIELD  = 31; // OBJECT, STRING -> DATUM
                         // | Sequence, STRING -> Sequence
        // Return an array containing the keys of the object.
        KEYS = 94; // OBJECT -> ARRAY
        // Check whether an object contains all the specified fields,
        // or filters a sequence so that all objects inside of it
        // contain all the specified fields.
        HAS_FIELDS = 32; // OBJECT, Pathspec... -> BOOL
        // x.with_fields(...) <=> x.has_fields(...).pluck(...)
        WITH_FIELDS = 96; // Sequence, Pathspec... -> Sequence
        // Get a subset of an object by selecting some attributes to preserve,
        // or map that over a sequence.  (Both pick and pluck, polymorphic.)
        PLUCK    = 33; // Sequence, Pathspec... -> Sequence | OBJECT, Pathspec... -> OBJECT
        // Get a subset of an object by selecting some attributes to discard, or
        // map that over a sequence.  (Both unpick and without, polymorphic.)
        WITHOUT  = 34; // Sequence, Pathspec... -> Sequence | OBJECT, Pathspec... -> OBJECT
        // Merge objects (right-preferential)
        MERGE    = 35; // OBJECT... -> OBJECT | Sequence -> Sequence

        // Sequence Ops
        // Get all elements of a sequence between two values.
        // Half-open by default, but the openness of either side can be
        // changed by passing 'closed' or 'open for `right_bound` or
        // `left_bound`.
        BETWEEN   = 36; // StreamSelection, DATUM, DATUM, {index:!STRING, right_bound:STRING, left_bound:STRING} -> StreamSelection
        REDUCE    = 37; // Sequence, Function(2), {base:DATUM} -> DATUM
        MAP       = 38; // Sequence, Function(1) -> Sequence

        // Filter a sequence with either a function or a shortcut
        // object (see API docs for details).  The body of FILTER is
        // wrapped in an implicit `.default(false)`, and you can
        // change the default value by specifying the `default`
        // optarg.  If you make the default `r.error`, all errors
        // caught by `default` will be rethrown as if the `default`
        // did not exist.
        FILTER    = 39; // Sequence, Function(1), {default:DATUM} -> Sequence |
                        // Sequence, OBJECT, {default:DATUM} -> Sequence
        // Map a function over a sequence and then concatenate the results together.
        CONCATMAP = 40; // Sequence, Function(1) -> Sequence
        // Order a sequence based on one or more attributes.
        ORDERBY   = 41; // Sequence, (!STRING | Ordering)... -> Sequence
        // Get all distinct elements of a sequence (like `uniq`).
        DISTINCT  = 42; // Sequence -> Sequence
        // Count the number of elements in a sequence, or only the elements that match
        // a given filter.
        COUNT     = 43; // Sequence -> NUMBER | Sequence, DATUM -> NUMBER | Sequence, Function(1) -> NUMBER
        IS_EMPTY = 86; // Sequence -> BOOL
        // Take the union of multiple sequences (preserves duplicate elements! (use distinct)).
        UNION     = 44; // Sequence... -> Sequence
        // Get the Nth element of a sequence.
        NTH       = 45; // Sequence, NUMBER -> DATUM
        // Takes a sequence, and three functions:
        // - A function to group the sequence by.
        // - A function to map over the groups.
        // - A reduction to apply to each of the groups.
        GROUPED_MAP_REDUCE = 46; // Sequence, Function(1), Function(1), Function(2), {base:DATUM} -> ARRAY
        // Groups a sequence by one or more attributes, and then applies a reduction.
        // The third argument is a special object literal giving the kind of operation to be
        // performed and any necessary arguments.
        // At present, GROUPBY suports the following operations
        // * {'COUNT': <ignored>} - count the size of the group
        // * {'SUM': attr} - sum the values of the given attribute across the group
        // * {'AVG': attr} - average the values of the given attribute across the group
        GROUPBY            = 47; // Sequence, ARRAY, !GROUP_BY_OBJECT -> Sequence
        INNER_JOIN         = 48; // Sequence, Sequence, Function(2) -> Sequence
        OUTER_JOIN         = 49; // Sequence, Sequence, Function(2) -> Sequence
        // An inner-join that does an equality comparison on two attributes.
        EQ_JOIN            = 50; // Sequence, !STRING, Sequence, {index:!STRING} -> Sequence
        ZIP                = 72; // Sequence -> Sequence

        // Array Ops
        // Insert an element in to an array at a given index.
        INSERT_AT          = 82; // ARRAY, NUMBER, DATUM -> ARRAY
        // Remove an element at a given index from an array.
        DELETE_AT          = 83; // ARRAY, NUMBER -> ARRAY |
                                 // ARRAY, NUMBER, NUMBER -> ARRAY
        // Change the element at a given index of an array.
        CHANGE_AT          = 84; // ARRAY, NUMBER, DATUM -> ARRAY
        // Splice one array in to another array.
        SPLICE_AT          = 85; // ARRAY, NUMBER, ARRAY -> ARRAY

        // * Type Ops
        // Coerces a datum to a named type (e.g. "bool").
        // If you previously used `stream_to_array`, you should use this instead
        // with the type "array".
        COERCE_TO = 51; // Top, STRING -> Top
        // Returns the named type of a datum (e.g. TYPEOF(true) = "BOOL")
        TYPEOF = 52; // Top -> STRING

        // * Write Ops (the OBJECTs contain data about number of errors etc.)
        // Updates all the rows in a selection.  Calls its Function with the row
        // to be updated, and then merges the result of that call.
        UPDATE   = 53; // StreamSelection, Function(1), {non_atomic:BOOL, durability:STRING, return_vals:BOOL} -> OBJECT |
                       // SingleSelection, Function(1), {non_atomic:BOOL, durability:STRING, return_vals:BOOL} -> OBJECT |
                       // StreamSelection, OBJECT,      {non_atomic:BOOL, durability:STRING, return_vals:BOOL} -> OBJECT |
                       // SingleSelection, OBJECT,      {non_atomic:BOOL, durability:STRING, return_vals:BOOL} -> OBJECT
        // Deletes all the rows in a selection.
        DELETE   = 54; // StreamSelection, {durability:STRING, return_vals:BOOL} -> OBJECT | SingleSelection -> OBJECT
        // Replaces all the rows in a selection.  Calls its Function with the row
        // to be replaced, and then discards it and stores the result of that
        // call.
        REPLACE  = 55; // StreamSelection, Function(1), {non_atomic:BOOL, durability:STRING, return_vals:BOOL} -> OBJECT | SingleSelection, Function(1), {non_atomic:BOOL, durability:STRING, return_vals:BOOL} -> OBJECT
        // Inserts into a table.  If `upsert` is true, overwrites entries with
        // the same primary key (otherwise errors).
        INSERT   = 56; // Table, OBJECT, {upsert:BOOL, durability:STRING, return_vals:BOOL} -> OBJECT | Table, Sequence, {upsert:BOOL, durability:STRING, return_vals:BOOL} -> OBJECT

        // * Administrative OPs
        // Creates a database with a particular name.
        DB_CREATE    = 57; // STRING -> OBJECT
        // Drops a database with a particular name.
        DB_DROP      = 58; // STRING -> OBJECT
        // Lists all the databases by name.  (Takes no arguments)
        DB_LIST      = 59; // -> ARRAY
        // Creates a table with a particular name in a particular
        // database.  (You may omit the first argument to use the
        // default database.)
        TABLE_CREATE = 60; // Database, STRING, {datacenter:STRING, primary_key:STRING, cache_size:NUMBER, durability:STRING} -> OBJECT
                           // STRING, {datacenter:STRING, primary_key:STRING, cache_size:NUMBER, durability:STRING} -> OBJECT
        // Drops a table with a particular name from a particular
        // database.  (You may omit the first argument to use the
        // default database.)
        TABLE_DROP   = 61; // Database, STRING -> OBJECT
                           // STRING -> OBJECT
        // Lists all the tables in a particular database.  (You may
        // omit the first argument to use the default database.)
        TABLE_LIST   = 62; // Database -> ARRAY
                           //  -> ARRAY
        // Ensures that previously issued soft-durability writes are complete and
        // written to disk.
        SYNC     = 138; // Table -> OBJECT

        // * Secondary indexes OPs
        // Creates a new secondary index with a particular name and definition.
        INDEX_CREATE = 75; // Table, STRING, Function(1), {multi:BOOL} -> OBJECT
        // Drops a secondary index with a particular name from the specified table.
        INDEX_DROP   = 76; // Table, STRING -> OBJECT
        // Lists all secondary indexes on a particular table.
        INDEX_LIST   = 77; // Table -> ARRAY
        // Gets information about whether or not a set of indexes are ready to
        // be accessed. Returns a list of objects that look like this:
        // {index:STRING, ready:BOOL[, blocks_processed:NUMBER, blocks_total:NUMBER]}
        INDEX_STATUS = 139; // Table, STRING... -> ARRAY
        // Blocks until a set of indexes are ready to be accessed. Returns the
        // same values INDEX_STATUS.
        INDEX_WAIT = 140; // Table, STRING... -> ARRAY

        // * Control Operators
        // Calls a function on data
        FUNCALL  = 64; // Function(*), DATUM... -> DATUM
        // Executes its first argument, and returns its second argument if it
        // got [true] or its third argument if it got [false] (like an `if`
        // statement).
        BRANCH  = 65; // BOOL, Top, Top -> Top
        // Returns true if any of its arguments returns true (short-circuits).
        // (Like `or` in most languages.)
        ANY     = 66; // BOOL... -> BOOL
        // Returns true if all of its arguments return true (short-circuits).
        // (Like `and` in most languages.)
        ALL     = 67; // BOOL... -> BOOL
        // Calls its Function with each entry in the sequence
        // and executes the array of terms that Function returns.
        FOREACH = 68; // Sequence, Function(1) -> OBJECT

////////////////////////////////////////////////////////////////////////////////
////////// Special Terms
////////////////////////////////////////////////////////////////////////////////

        // An anonymous function.  Takes an array of numbers representing
        // variables (see [VAR] above), and a [Term] to execute with those in
        // scope.  Returns a function that may be passed an array of arguments,
        // then executes the Term with those bound to the variable names.  The
        // user will never construct this directly.  We use it internally for
        // things like `map` which take a function.  The "arity" of a [Function] is
        // the number of arguments it takes.
        // For example, here's what `_X_.map{|x| x+2}` turns into:
        // Term {
        //   type = MAP;
        //   args = [_X_,
        //           Term {
        //             type = Function;
        //             args = [Term {
        //                       type = DATUM;
        //                       datum = Datum {
        //                         type = R_ARRAY;
        //                         r_array = [Datum { type = R_NUM; r_num = 1; }];
        //                       };
        //                     },
        //                     Term {
        //                       type = ADD;
        //                       args = [Term {
        //                                 type = VAR;
        //                                 args = [Term {
        //                                           type = DATUM;
        //                                           datum = Datum { type = R_NUM;
        //                                                           r_num = 1};
        //                                         }];
        //                               },
        //                               Term {
        //                                 type = DATUM;
        //                                 datum = Datum { type = R_NUM; r_num = 2; };
        //                               }];
        //                     }];
        //           }];
        FUNC = 69; // ARRAY, Top -> ARRAY -> Top

        // Indicates to ORDER_BY that this attribute is to be sorted in ascending order.
        ASC = 73; // !STRING -> Ordering
        // Indicates to ORDER_BY that this attribute is to be sorted in descending order.
        DESC = 74; // !STRING -> Ordering

        // Gets info about anything.  INFO is most commonly called on tables.
        INFO = 79; // Top -> OBJECT

        // `a.match(b)` returns a match object if the string `a`
        // matches the regular expression `b`.
        MATCH = 97; // STRING, STRING -> DATUM

        // Select a number of elements from sequence with uniform distribution.
        SAMPLE = 81; // Sequence, NUMBER -> Sequence

        // Evaluates its first argument.  If that argument returns
        // NULL or throws an error related to the absence of an
        // expected value (for instance, accessing a non-existent
        // field or adding NULL to an integer), DEFAULT will either
        // return its second argument or execute it if it's a
        // function.  If the second argument is a function, it will be
        // passed either the text of the error or NULL as its
        // argument.
        DEFAULT = 92; // Top, Top -> Top

        // Parses its first argument as a json string and returns it as a
        // datum.
        JSON = 98; // STRING -> DATUM

        // Parses its first arguments as an ISO 8601 time and returns it as a
        // datum.
        ISO8601 = 99; // STRING -> PSEUDOTYPE(TIME)
        // Prints a time as an ISO 8601 time.
        TO_ISO8601 = 100; // PSEUDOTYPE(TIME) -> STRING

        // Returns a time given seconds since epoch in UTC.
        EPOCH_TIME = 101; // NUMBER -> PSEUDOTYPE(TIME)
        // Returns seconds since epoch in UTC given a time.
        TO_EPOCH_TIME = 102; // PSEUDOTYPE(TIME) -> NUMBER

        // The time the query was received by the server.
        NOW = 103; // -> PSEUDOTYPE(TIME)
        // Puts a time into an ISO 8601 timezone.
        IN_TIMEZONE = 104; // PSEUDOTYPE(TIME), STRING -> PSEUDOTYPE(TIME)
        // a.during(b, c) returns whether a is in the range [b, c)
        DURING = 105; // PSEUDOTYPE(TIME), PSEUDOTYPE(TIME), PSEUDOTYPE(TIME) -> BOOL
        // Retrieves the date portion of a time.
        DATE = 106; // PSEUDOTYPE(TIME) -> PSEUDOTYPE(TIME)
        // x.time_of_day == x.date - x
        TIME_OF_DAY = 126; // PSEUDOTYPE(TIME) -> NUMBER
        // Returns the timezone of a time.
        TIMEZONE = 127; // PSEUDOTYPE(TIME) -> STRING

        // These access the various components of a time.
        YEAR = 128; // PSEUDOTYPE(TIME) -> NUMBER
        MONTH = 129; // PSEUDOTYPE(TIME) -> NUMBER
        DAY = 130; // PSEUDOTYPE(TIME) -> NUMBER
        DAY_OF_WEEK = 131; // PSEUDOTYPE(TIME) -> NUMBER
        DAY_OF_YEAR = 132; // PSEUDOTYPE(TIME) -> NUMBER
        HOURS = 133; // PSEUDOTYPE(TIME) -> NUMBER
        MINUTES = 134; // PSEUDOTYPE(TIME) -> NUMBER
        SECONDS = 135; // PSEUDOTYPE(TIME) -> NUMBER

        // Construct a time from a date and optional timezone or a
        // date+time and optional timezone.
        TIME = 136; // NUMBER, NUMBER, NUMBER -> PSEUDOTYPE(TIME) |
                    // NUMBER, NUMBER, NUMBER, STRING -> PSEUDOTYPE(TIME) |
                    // NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, NUMBER -> PSEUDOTYPE(TIME) |
                    // NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, STRING -> PSEUDOTYPE(TIME) |

        // Constants for ISO 8601 days of the week.
        MONDAY = 107;    // -> 1
        TUESDAY = 108;   // -> 2
        WEDNESDAY = 109; // -> 3
        THURSDAY = 110;  // -> 4
        FRIDAY = 111;    // -> 5
        SATURDAY = 112;  // -> 6
        SUNDAY = 113;    // -> 7

        // Constants for ISO 8601 months.
        JANUARY = 114;   // -> 1
        FEBRUARY = 115;  // -> 2
        MARCH = 116;     // -> 3
        APRIL = 117;     // -> 4
        MAY = 118;       // -> 5
        JUNE = 119;      // -> 6
        JULY = 120;      // -> 7
        AUGUST = 121;    // -> 8
        SEPTEMBER = 122; // -> 9
        OCTOBER = 123;   // -> 10
        NOVEMBER = 124;  // -> 11
        DECEMBER = 125;  // -> 12

        // Indicates to MERGE to replace the other object rather than merge it.
        LITERAL = 137; // JSON -> Merging
    }
    optional TermType type = 1;

    // This is only used when type is DATUM.
    optional Datum datum = 2;

    repeated Term args = 3; // Holds the positional arguments of the query.
    message AssocPair {
        optional string key = 1;
        optional Term val = 2;
    }
    repeated AssocPair optargs = 4; // Holds the optional arguments of the query.
    // (Note that the order of the optional arguments doesn't matter; think of a
    // Hash.)

    extensions 10000 to 20000;
}

////////////////////////////////////////////////////////////////////////////////
//                                  EXAMPLE                                   //
////////////////////////////////////////////////////////////////////////////////
//   ```ruby
//   r.table('tbl', {:use_outdated => true}).insert([{:id => 0}, {:id => 1}])
//   ```
// Would turn into:
//   Term {
//     type = INSERT;
//     args = [Term {
//               type = TABLE;
//               args = [Term {
//                         type = DATUM;
//                         datum = Datum { type = R_STR; r_str = "tbl"; };
//                       }];
//               optargs = [["use_outdated",
//                           Term {
//                             type = DATUM;
//                             datum = Datum { type = R_BOOL; r_bool = true; };
//                           }]];
//             },
//             Term {
//               type = MAKE_ARRAY;
//               args = [Term {
//                         type = DATUM;
//                         datum = Datum { type = R_OBJECT; r_object = [["id", 0]]; };
//                       },
//                       Term {
//                         type = DATUM;
//                         datum = Datum { type = R_OBJECT; r_object = [["id", 1]]; };
//                       }];
//             }]
//   }
// And the server would reply:
//   Response {
//     type = SUCCESS_ATOM;
//     token = 1;
//     response = [Datum { type = R_OBJECT; r_object = [["inserted", 2]]; }];
//   }
// Or, if there were an error:
//   Response {
//     type = RUNTIME_ERROR;
//     token = 1;
//     response = [Datum { type = R_STR; r_str = "The table `tbl` doesn't exist!"; }];
//     backtrace = [Frame { type = POS; pos = 0; }, Frame { type = POS; pos = 0; }];
//   }
