<commit_before>////////////////////////////////////////////////////////////////////////////////
//                            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.

// 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;
    }
}

// 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.
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.
    }
    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];

    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].

        // 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.
}

// 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;
    }
    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
//   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 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.
        ERROR        = 12; // STRING -> 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, JSON {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
        SLICE  = 30; // Sequence, NUMBER, NUMBER -> Sequence
        SKIP  = 70; // Sequence, NUMBER -> Sequence
        LIMIT = 71; // Sequence, NUMBER -> Sequence

        // Stream/Object Ops
        // Get a particular attribute out of an object, or map that over a
        // sequence.
        GETATTR  = 31; // OBJECT, STRING -> DATUM
        // Check whether an object contains all of a set of attributes, or map
        // that over a sequence.
        CONTAINS = 32; // OBJECT, STRING... -> BOOL
        // 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, STRING... -> Sequence | OBJECT, STRING... -> 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, STRING... -> Sequence | OBJECT, STRING... -> OBJECT
        // Merge objects (right-preferential)
        MERGE    = 35; // OBJECT... -> OBJECT | Sequence -> Sequence

        // Sequence Ops
        // Get all elements of a sequence between two values.
        BETWEEN   = 36; // StreamSelection, DATUM, DATUM, {:index:!STRING} -> StreamSelection
        REDUCE    = 37; // Sequence, Function(2), {base:DATUM} -> DATUM
        MAP       = 38; // Sequence, Function(1) -> Sequence
        FILTER    = 39; // Sequence, Function(1) -> Sequence | Sequence, OBJECT -> 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.
        COUNT     = 43; // Sequence -> NUMBER
        // 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} -> Sequence
        // 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


        // * 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} -> OBJECT |
                       // SingleSelection, Function(1), {non_atomic:BOOL} -> OBJECT |
                       // StreamSelection, OBJECT,      {non_atomic:BOOL} -> OBJECT |
                       // SingleSelection, OBJECT,      {non_atomic:BOOL} -> OBJECT
        // Deletes all the rows in a selection.
        DELETE   = 54; // StreamSelection -> 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} -> OBJECT | SingleSelection, Function(1), {non_atomic: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} -> OBJECT | Table, Sequence, {upsert: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, hard_durability:BOOL} -> OBJECT
                           // STRING, {datacenter:STRING, primary_key:STRING, cache_size:NUMBER, hard_durability:BOOL} -> 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

        // * Secondary indexes OPs
        // Creates a new secondary index with a particular name and definition.
        INDEX_CREATE = 75; // Table, STRING, Function(1) -> 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

        // * 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
    }
    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; }];
//   }
<commit_msg>updated PROTO file.<commit_after>////////////////////////////////////////////////////////////////////////////////
//                            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.

// 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;
    }
}

// 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.
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.
    }
    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];

    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].

        // 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.
}

// 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;
    }
    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
//   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 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.
        ERROR        = 12; // STRING -> 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, JSON {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
        SLICE  = 30; // Sequence, NUMBER, NUMBER -> Sequence
        SKIP  = 70; // Sequence, NUMBER -> Sequence
        LIMIT = 71; // Sequence, NUMBER -> Sequence

        // Stream/Object Ops
        // Get a particular attribute out of an object, or map that over a
        // sequence.
        GETATTR  = 31; // OBJECT, STRING -> DATUM
        // Check whether an object contains all of a set of attributes, or map
        // that over a sequence.
        CONTAINS = 32; // OBJECT, STRING... -> BOOL
        // 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, STRING... -> Sequence | OBJECT, STRING... -> 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, STRING... -> Sequence | OBJECT, STRING... -> OBJECT
        // Merge objects (right-preferential)
        MERGE    = 35; // OBJECT... -> OBJECT | Sequence -> Sequence

        // Sequence Ops
        // Get all elements of a sequence between two values.
        BETWEEN   = 36; // StreamSelection, DATUM, DATUM, {:index:!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.rethrow`, 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.
        COUNT     = 43; // Sequence -> NUMBER
        // 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} -> Sequence
        // 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


        // * 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} -> OBJECT |
                       // SingleSelection, Function(1), {non_atomic:BOOL} -> OBJECT |
                       // StreamSelection, OBJECT,      {non_atomic:BOOL} -> OBJECT |
                       // SingleSelection, OBJECT,      {non_atomic:BOOL} -> OBJECT
        // Deletes all the rows in a selection.
        DELETE   = 54; // StreamSelection -> 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} -> OBJECT | SingleSelection, Function(1), {non_atomic: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} -> OBJECT | Table, Sequence, {upsert: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, hard_durability:BOOL} -> OBJECT
                           // STRING, {datacenter:STRING, primary_key:STRING, cache_size:NUMBER, hard_durability:BOOL} -> 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

        // * Secondary indexes OPs
        // Creates a new secondary index with a particular name and definition.
        INDEX_CREATE = 75; // Table, STRING, Function(1) -> 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

        // * 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

        // 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 = 80; // Top, Top -> Top
        // If an error is being handled, rethrow that error, otherwise
        // return NULL.  (You would usually put this inside of the
        // second argument to DEFAULT or else specify it as the
        // `default` optarg for filter.)
        RETHROW = 81; // -> NULL
    }
    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; }];
//   }

{'fraction_non_alphanumeric': 0.1225185650036607, 'fraction_numerical': 0.01125405292333438, 'mean_word_length': 1.5000522957849598, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 203, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 60, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5256379', 'n_tokens_mistral': 13311, 'n_tokens_neox': 12175, 'n_words': 5272}