Repository: basho/riak-nodejs-client (js)

Issue:
Search does not return key in _yz_rk [JIRA: CLIENTS-908]
When using Riak.Commands.YZ.Search.Builder, I get incorrect `_yz_rk` values. I expect the key of the item, but I get what seems like gibberish. `_yz_id` values are also not what I would expect.

For example, this is one of the returned docs from the node code:

```json
{
  "score": 1,
  "_yz_rb": "ssh-sessions",
  "_yz_rt": "ssh-sessions",
  "_yz_rk": 400000,
  "_yz_id": 1,
  "hardwareId": 2,
  "state": "connected"
}
```

and the corresponding doc returned from a curl request: `curl "http://localhost:8098/search/query/ssh-sessions?wt=json&q=hardwareId:\[0%20TO%20100\]"`

```json
{
  "state": "connected",
  "hardwareId": 2,
  "_yz_id": "1*ssh-sessions*ssh-sessions*4e05ed89-2a49-4f17-8885-ca79f0d292c0*41",
  "_yz_rk": "4e05ed89-2a49-4f17-8885-ca79f0d292c0",
  "_yz_rt": "ssh-sessions",
  "_yz_rb": "ssh-sessions"
}
```

This is in a test environment that has two nodes in a cluster.

I went as far as uninstalling riak from each of these servers, deleting all of /var/lib/riak, reinstalling, and then setting up just this search index with the four dummy values, and it continues to be a problem.

If there's any other information I can provide, let me know. I'm just trying to get spun up on riak development, so I'm not sure what to check or what to try next.

## Additional information

Component|Version
:----|-----:
riak|2.1.4
Ubuntu|14.04.4
basho-riak-client|2.2.1
node|6.2.2


<details>
  <summary>ssh-sessions.xml schema definition</summary>

```xml
<?xml version="1.0" encoding="UTF-8" ?>
<schema name="default" version="1.5">
    <fields>
        <field name="hardwareId" type="long"   indexed="true" stored="true"  multiValued="false"/>
        <field name="state"      type="string" indexed="true" stored="true"  multiValued="false"/>
        <field name="host"       type="string" indexed="true" stored="false" multiValued="false"/>
        <field name="port"       type="int"    indexed="true" stored="false" multiValued="false"/>

        <field name="_yz_id" type="_yz_str" indexed="true" stored="true" multiValued="false" required="true"/>
        <!-- Entropy Data: Data related to anti-entropy -->
        <field name="_yz_ed" type="_yz_str" indexed="true" stored="false" multiValued="false"/>
        <!-- Partition Number: Used as a filter query param -->
        <field name="_yz_pn" type="_yz_str" indexed="true" stored="false" multiValued="false"/>
        <!-- First Partition Number: The first partition in this doc's
            preflist, used for further filtering on overlapping partitions. -->
        <field name="_yz_fpn" type="_yz_str" indexed="true" stored="false" multiValued="false"/>
        <!-- If there is a sibling, use vtag to differentiate them -->
        <field name="_yz_vtag" type="_yz_str" indexed="true" stored="false" multiValued="false"/>
        <!-- Riak Key: The key of the Riak object this doc corresponds to. -->
        <field name="_yz_rk" type="_yz_str" indexed="true" stored="true" multiValued="false"/>
        <!-- Riak Bucket Type: The bucket type of the Riak object this doc corresponds to. -->
        <field name="_yz_rt" type="_yz_str" indexed="true" stored="true" multiValued="false"/>
        <!-- Riak Bucket: The bucket of the Riak object this doc corresponds to. -->
        <field name="_yz_rb" type="_yz_str" indexed="true" stored="true" multiValued="false"/>
        <!-- Flag indicating if this doc is the product of a failed object extraction -->
        <field name="_yz_err" type="_yz_str" indexed="true" stored="false" multiValued="false"/>

        <dynamicField name="*" type="ignored"  />
    </fields>

    <uniqueKey>_yz_id</uniqueKey>

    <types>
        <!-- YZ String: Used for non-analyzed fields -->
        <fieldType name="_yz_str" class="solr.StrField" sortMissingLast="true" />

        <fieldType name="string" class="solr.StrField" sortMissingLast="true" />
        <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>

        <fieldType name="int" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/>
        <fieldType name="float" class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/>
        <fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
        <fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" positionIncrementGap="0"/>

        <fieldtype name="ignored" stored="false" indexed="false" multiValued="true" class="solr.StrField" />
    </types>
</schema>
```

</details>

<details>
  <summary>Index set up commands</summary>

```bash
# Create the schema for the ssh-sessions index
curl -X PUT http://localhost:8098/search/schema/ssh-sessions -H "Content-Type: application/xml" --data-binary @ssh-sessions.xml
# Create the ssh-search index itself
curl -X PUT http://localhost:8098/search/index/ssh-sessions -H "Content-Type: application/json" -d '{"schema":"ssh-sessions"}'
# Create the bucket type
sudo riak-admin bucket-type create ssh-sessions '{"props":{"search_index":"ssh-sessions","allow_mult":true}}'
# Activate the bucket type
sudo riak-admin bucket-type activate ssh-sessions
```

</details>

<details>
  <summary>riak-search.js output (incorrect)</summary>

```json
{
  "numFound": 4,
  "maxScore": 1,
  "docs": [
    {
      "score": 1,
      "_yz_rb": "ssh-sessions",
      "_yz_rt": "ssh-sessions",
      "_yz_rk": 9,
      "_yz_id": 1,
      "hardwareId": 1,
      "state": "request-connect"
    },
    {
      "score": 1,
      "_yz_rb": "ssh-sessions",
      "_yz_rt": "ssh-sessions",
      "_yz_rk": 400000,
      "_yz_id": 1,
      "hardwareId": 2,
      "state": "connected"
    },
    {
      "score": 1,
      "_yz_rb": "ssh-sessions",
      "_yz_rt": "ssh-sessions",
      "_yz_rk": 9490,
      "_yz_id": 1,
      "hardwareId": 3,
      "state": "request-disconnect"
    },
    {
      "score": 1,
      "_yz_rb": "ssh-sessions",
      "_yz_rt": "ssh-sessions",
      "_yz_rk": 862,
      "_yz_id": 1,
      "hardwareId": 4,
      "state": "disconnected"
    }
  ]
}
```

</details>

<details>
  <summary>curl output (correct)</summary>

```json
{
  "responseHeader": {
    "status": 0,
    "QTime": 18,
    "params": {
      "shards": "192.168.1.135:8093/internal_solr/ssh-sessions",
      "q": "hardwareId:[0 TO 100]",
      "192.168.1.135:8093": "(_yz_pn:62 AND (_yz_fpn:62)) OR _yz_pn:61 OR (_yz_pn:58 AND (_yz_fpn:58)) OR _yz_pn:57 OR (_yz_pn:54 AND (_yz_fpn:54)) OR _yz_pn:53 OR (_yz_pn:50 AND (_yz_fpn:50)) OR _yz_pn:49 OR (_yz_pn:46 AND (_yz_fpn:46)) OR _yz_pn:45 OR (_yz_pn:42 AND (_yz_fpn:42)) OR _yz_pn:41 OR (_yz_pn:38 AND (_yz_fpn:38)) OR _yz_pn:37 OR (_yz_pn:34 AND (_yz_fpn:34)) OR _yz_pn:33 OR (_yz_pn:30 AND (_yz_fpn:30)) OR _yz_pn:29 OR (_yz_pn:26 AND (_yz_fpn:26)) OR _yz_pn:25 OR (_yz_pn:22 AND (_yz_fpn:22)) OR _yz_pn:21 OR (_yz_pn:18 AND (_yz_fpn:18)) OR _yz_pn:17 OR (_yz_pn:14 AND (_yz_fpn:14)) OR _yz_pn:13 OR (_yz_pn:10 AND (_yz_fpn:10)) OR _yz_pn:9 OR (_yz_pn:6 AND (_yz_fpn:6)) OR _yz_pn:5 OR (_yz_pn:2 AND (_yz_fpn:2)) OR _yz_pn:1",
      "wt": "json"
    }
  },
  "response": {
    "numFound": 4,
    "start": 0,
    "maxScore": 1,
    "docs": [
      {
        "state": "request-connect",
        "hardwareId": 1,
        "_yz_id": "1*ssh-sessions*ssh-sessions*9cdfe8d5-dd41-45f9-88bb-735c48ac3f15*41",
        "_yz_rk": "9cdfe8d5-dd41-45f9-88bb-735c48ac3f15",
        "_yz_rt": "ssh-sessions",
        "_yz_rb": "ssh-sessions"
      },
      {
        "state": "connected",
        "hardwareId": 2,
        "_yz_id": "1*ssh-sessions*ssh-sessions*4e05ed89-2a49-4f17-8885-ca79f0d292c0*41",
        "_yz_rk": "4e05ed89-2a49-4f17-8885-ca79f0d292c0",
        "_yz_rt": "ssh-sessions",
        "_yz_rb": "ssh-sessions"
      },
      {
        "state": "request-disconnect",
        "hardwareId": 3,
        "_yz_id": "1*ssh-sessions*ssh-sessions*09490ce5-6c0e-4004-ac27-1b7f361dde4e*17",
        "_yz_rk": "09490ce5-6c0e-4004-ac27-1b7f361dde4e",
        "_yz_rt": "ssh-sessions",
        "_yz_rb": "ssh-sessions"
      },
      {
        "state": "disconnected",
        "hardwareId": 4,
        "_yz_id": "1*ssh-sessions*ssh-sessions*862b4a4f-f1f4-4f39-b3f1-cc8c66ee63db*1",
        "_yz_rk": "862b4a4f-f1f4-4f39-b3f1-cc8c66ee63db",
        "_yz_rt": "ssh-sessions",
        "_yz_rb": "ssh-sessions"
      }
    ]
  }
}
```

</details>

<details>
  <summary>riak-search.js – node.js code used to search</summary>

```js
const Riak = require('basho-riak-client');

const bucketType = 'ssh-sessions';
const bucket = 'ssh-sessions';

const client = new Riak.Client(['127.0.0.1:8087'], (err, c) => {
    if (err) {
        console.log(err);
        return;
    }

    const search = new Riak.Commands.YZ.Search.Builder()
        .withIndexName('ssh-sessions')
        .withQuery('hardwareId:[0 TO 100]')
        .withCallback((err, rslt) => {
            if (err) {
                console.log(err);
                return;
            }

            console.log(rslt);
            c.stop(() => {});
        })
        .build();
    c.execute(search);
});
```

</details>

<details>
  <summary>riak-populate.js – the code I used to populate the data</summary>

```js
const Riak = require('basho-riak-client');
const async = require('async');

const data = {
    '9cdfe8d5-dd41-45f9-88bb-735c48ac3f15': {
        hardwareId: 1,
        state: 'request-connect'
    },
    '4e05ed89-2a49-4f17-8885-ca79f0d292c0': {
        hardwareId: 2,
        state: 'connected',
        host: 'host1',
        port: 22
    },
    '09490ce5-6c0e-4004-ac27-1b7f361dde4e': {
        hardwareId: 3,
        state: 'request-disconnect',
        host: 'host2',
        port: 22
    },
    '862b4a4f-f1f4-4f39-b3f1-cc8c66ee63db': {
        hardwareId: 4,
        state: 'disconnected'
    },
};

const bucketType = 'ssh-sessions';
const bucket = 'ssh-sessions';

new Riak.Client(['127.0.0.1:8087'], (err, c) => {
    if (err) {
        console.log(err);
        return;
    }

    function populateKey(key, value, callback) {
        c.fetchValue({ bucketType, bucket, key, convertToJs: true }, (err, rslt) => {
            if (rslt.isNotFound) {
                c.storeValue({ bucketType, bucket, key, value: data[key] }, (err, rslt) => {
                    if (err) {
                        return callback(err);
                    }

                    console.log(`${key} stored.`);
                    return callback(null);
                });
            }
            else {
                const riakObj = rslt.values[0];
                const value = riakObj.value;
                value.date = new Date().toISOString();
                riakObj.setValue(value);

                c.storeValue({ value: riakObj }, (err, rslt) => {
                    if (err) {
                        return callback(err);
                    }

                    console.log(`${key} updated.`);
                    return callback(null);
                });
            }
        });
    }

    async.parallel(
        Object.keys(data).map(key => {
            const value = data[key];
            return callback => populateKey(key, value, callback);
        }),
        (err, results) => {
            if (err) {
                console.log(err);
                c.stop(() => {});
                return;
            }

            c.stop(() => {});
        }
    );
});
```

</details>

Pull request description:
READY: Riak Search document decoding / parsing bug
Fixes #165 (CLIENTS-908) 

Patch:
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..554c4f0
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,22 @@
+## How-to contribute to the Riak Node.js client
+
+**_IMPORTANT_**: This is an open source project licensed under the Apache 2.0 License. We encourage contributions to the project from the community. We ask that you keep in mind these considerations when planning your contribution.
+
+* Whether your contribution is for a bug fix or a feature request, **create an [Issue](https://github.com/basho/riak-nodejs-client/issues)** and let us know what you are thinking.
+* **For bugs**, if you have already found a fix, feel free to submit a Pull Request referencing the Issue you created.
+* **For feature requests**, we want to improve upon the library incrementally which means small changes at a time. In order ensure your PR can be reviewed in a timely manner, please keep PRs small, e.g. <10 files and <500 lines changed. If you think this is unrealistic, then mention that within the Issue and we can discuss it.
+
+### Pull Request Process
+
+Here’s how to get started:
+
+* Fork the appropriate sub-projects that are affected by your change. 
+* Create a topic branch for your change and checkout that branch.
+     `git checkout -b some-topic-branch`
+     * Make your changes and run the test suite if one is provided. (see below)
+     * Commit your changes and push them to your fork.
+     * Open pull-requests for the appropriate projects.
+     * Contributors will review your pull request, suggest changes, and merge it when it’s ready and/or offer feedback.
+     * To report a bug or issue, please open a new issue against this repository.
+
+You can [read the full guidelines for bug reporting and code contributions](http://docs.basho.com/riak/latest/community/bugs/) on the Riak Docs.
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..fac1816
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,11 @@
+Please ensure the following information is supplied for new issues:
+
+- [ ] Riak Node.js Client version
+- [ ] Node.js version
+- [ ] Riak version
+- [ ] Operating System / Distribution & Version
+- [ ] Riak `error.log` file, if applicable
+- [ ] What commands were being executed during the error
+- [ ] What you *expected* to have happen
+
+Thank you!
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..a7872df
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,8 @@
+Please ensure the following is present in your Pull Request:
+
+- [ ] Unit tests for your change
+- [ ] Integration tests (if applicable)
+
+Pull Requests that are small and limited in scope are most welcome.
+
+Thank you!
diff --git a/README.md b/README.md
index bd0c525..aef038a 100644
--- a/README.md
+++ b/README.md
@@ -73,3 +73,4 @@ Thank you to all of our contributors!
 * [Iain Proctor](https://github.com/iproctor)
 * [Brian Edgerton](https://github.com/brianedgerton)
 * [Samuel](https://github.com/faust64)
+* [Bryan Burgers](https://github.com/bryanburgers)
diff --git a/RELNOTES.md b/RELNOTES.md
index e6ca591..938f169 100644
--- a/RELNOTES.md
+++ b/RELNOTES.md
@@ -1,6 +1,8 @@
 Release Notes
 =============
 
+* [2.2.2](https://github.com/basho/riak-nodejs-client/issues?q=milestone%3Ariak-nodejs-client-2.2.2) - Following issues / PRs addressed:
+ * [Add `convertDocuments` search option to allow *not* converting Solr documents. Do not convert well-known Riak/Solr fields `_yz_*`](https://github.com/basho/riak-nodejs-client/pull/166)
 * [2.2.1](https://github.com/basho/riak-nodejs-client/issues?q=milestone%3Ariak-nodejs-client-2.2.1) - Following issues / PRs addressed:
  * [Fix uncaught exception when connection closes on a connection that had never executed a command](https://github.com/basho/riak-nodejs-client/pull/163)
 * [2.2.0](https://github.com/basho/riak-nodejs-client/issues?q=milestone%3Ariak-nodejs-client-2.2.0) - Following issues / PRs addressed:
diff --git a/lib/commands/yokozuna/search.js b/lib/commands/yokozuna/search.js
index 3716b7a..5c585ea 100644
--- a/lib/commands/yokozuna/search.js
+++ b/lib/commands/yokozuna/search.js
@@ -41,6 +41,7 @@ var utils = require('../../utils');
  * @param {String} [options.defaultOperation] Set the default operation. Allowed settings are either “and” or “or”.
  * @param {String[]} [options.returnFields] Only return the provided fields.
  * @param {String} [options.presort] Sorts all of the results. Either "key" or "score".
+ * @param {Boolean} [options.convertDocuments] Convert Solr document values to JS types.
  * @param {Function} callback The callback to execute when the comman completes.
  * @param {String} callback.err an error message. Will be null if no error.
  * @param {Object} callback.response the response from Riak (Solr)
@@ -87,6 +88,19 @@ Search.prototype.constructPbRequest = function() {
 
 };
 
+// https://github.com/basho/yokozuna/blob/develop/include/yokozuna.hrl#L340-L404
+function isYzField(f) {
+    return f === '_yz_id'   ||
+           f === '_yz_ed'   ||
+           f === '_yz_fpn'  ||
+           f === '_yz_vtag' ||
+           f === '_yz_pn'   ||
+           f === '_yz_rk'   ||
+           f === '_yz_rt'   ||
+           f === '_yz_rb'   ||
+           f === '_yz_err';
+}
+
 Search.prototype.onSuccess = function(rpbSearchQueryResp) {
 
     var docsToReturn = new Array(rpbSearchQueryResp.docs.length);
@@ -95,18 +109,21 @@ Search.prototype.onSuccess = function(rpbSearchQueryResp) {
         for (var j = 0; j < rpbSearchQueryResp.docs[i].fields.length; j++) {
             var key = rpbSearchQueryResp.docs[i].fields[j].key.toString('utf8');
             var value = rpbSearchQueryResp.docs[i].fields[j].value.toString('utf8');
-            // Search and MapReduce are effectively broken with the PB API because
-            // everything is returned as a string.
-            var valAsNum = utils.maybeIsNumber(value);
-            if (valAsNum) {
-                // it's a Long or number.
-                value = valAsNum;
-            } else if (value === 'null') {
-                // It's actually null
-                value = null;
-            } else {
-                // might also be a boolean.
-                value = value === 'true' || (value === 'false' ? false : value);
+            // GH-165 do not convert well-known YZ fields
+            if (isYzField(key) === false && this.options.convertDocuments === true) {
+                // Search and MapReduce are effectively broken with the PB API because
+                // everything is returned as a string.
+                var valAsNum = utils.maybeIsNumber(value);
+                if (valAsNum) {
+                    // it's a Long or number.
+                    value = valAsNum;
+                } else if (value === 'null') {
+                    // It's actually null
+                    value = null;
+                } else {
+                    // might also be a boolean.
+                    value = value === 'true' || (value === 'false' ? false : value);
+                }
             }
             //Support multiple values for the same key
             if (doc.hasOwnProperty(key)) {
@@ -140,7 +157,8 @@ var schema = Joi.object().keys({
     defaultField: Joi.string().default(null).optional(),
     defaultOperation: Joi.string().default(null).optional(),
     returnFields: Joi.array().default([]).optional(),
-    presort: Joi.string().default(null).optional()
+    presort: Joi.string().default(null).optional(),
+    convertDocuments: Joi.boolean().default(true).optional()
 });
 
 /**
@@ -273,6 +291,16 @@ Builder.prototype = {
        this.presort = presort;
        return this;
    },
+   /**
+    * Convert values in documents returned by Solr to corresponding Javascript types.
+    * @method convertDocuments
+    * @param {Boolean} convert Solr document values to JS types.
+    * @chainable
+    */
+   withConvertDocuments : function(convertDocuments) {
+       this.convertDocuments = convertDocuments;
+       return this;
+   },
    /**
      * Set the callback to be executed when the operation completes.
      * @method withCallback


Test patch:
diff --git a/test/unit/yokozuna/search.js b/test/unit/yokozuna/search.js
index 9b1e315..d32dd1e 100644
--- a/test/unit/yokozuna/search.js
+++ b/test/unit/yokozuna/search.js
@@ -109,6 +109,142 @@ describe('Search', function() {
             search.onSuccess(resp);
         });
 
+        it('processes-RpbSearchQueryResp-no-conversion-gh-165', function(done) {
+            /*
+                {
+                "state": "connected",
+                "hardwareId": 2,
+                "_yz_id": "1*ssh-sessions*ssh-sessions*4e05ed89-2a49-4f17-8885-ca79f0d292c0*41",
+                "_yz_rk": "4e05ed89-2a49-4f17-8885-ca79f0d292c0",
+                "_yz_rt": "ssh-sessions",
+                "_yz_rb": "ssh-sessions"
+                }
+            */
+            var resp = new RpbSearchQueryResp();
+            var doc = new RpbSearchDoc();
+            var pair = new RpbPair();
+            pair.key = new Buffer('state');
+            pair.value = new Buffer('connected');
+            doc.fields.push(pair);
+
+            pair = new RpbPair();
+            pair.key = new Buffer('hardwareId');
+            pair.value = new Buffer('2');
+            doc.fields.push(pair);
+
+            pair = new RpbPair();
+            pair.key = new Buffer('_yz_id');
+            pair.value = new Buffer('1*ssh-sessions*ssh-sessions*4e05ed89-2a49-4f17-8885-ca79f0d292c0*41');
+            doc.fields.push(pair);
+
+            pair = new RpbPair();
+            pair.key = new Buffer('_yz_rk');
+            pair.value = new Buffer('4e05ed89-2a49-4f17-8885-ca79f0d292c0');
+            doc.fields.push(pair);
+
+            pair = new RpbPair();
+            pair.key = new Buffer('_yz_rt');
+            pair.value = new Buffer('ssh-sessions');
+            doc.fields.push(pair);
+
+            pair = new RpbPair();
+            pair.key = new Buffer('_yz_rb');
+            pair.value = new Buffer('ssh-sessions');
+            doc.fields.push(pair);
+
+            resp.docs.push(doc);
+            resp.max_score = 1.123;
+            resp.num_found = 1;
+
+            var callback = function(err, response) {
+                assert.equal(response.numFound, 1);
+                assert.equal(response.maxScore, 1.123);
+                assert.equal(response.docs.length, 1);
+                var doc = response.docs[0];
+                assert.strictEqual(doc.state, 'connected');
+                assert.strictEqual(doc.hardwareId, '2');
+                assert.strictEqual(doc._yz_id, '1*ssh-sessions*ssh-sessions*4e05ed89-2a49-4f17-8885-ca79f0d292c0*41');
+                assert.strictEqual(doc._yz_rk, '4e05ed89-2a49-4f17-8885-ca79f0d292c0');
+                assert.strictEqual(doc._yz_rt, 'ssh-sessions');
+                assert.strictEqual(doc._yz_rb, 'ssh-sessions');
+                done();
+            };
+
+            var search = new Search.Builder()
+                    .withIndexName('indexName')
+                    .withQuery('some solr query')
+                    .withConvertDocuments(false)
+                    .withCallback(callback)
+                    .build();
+            search.onSuccess(resp);
+        });
+
+        it('processes-RpbSearchQueryResp-with-conversion-gh-165', function(done) {
+            var resp = new RpbSearchQueryResp();
+            var doc = new RpbSearchDoc();
+            var pair = new RpbPair();
+            pair.key = new Buffer('state');
+            pair.value = new Buffer('connected');
+            doc.fields.push(pair);
+
+            pair = new RpbPair();
+            pair.key = new Buffer('hardwareId');
+            pair.value = new Buffer('2');
+            doc.fields.push(pair);
+
+            pair = new RpbPair();
+            pair.key = new Buffer('booleanValue');
+            pair.value = new Buffer('true');
+            doc.fields.push(pair);
+
+            pair = new RpbPair();
+            pair.key = new Buffer('_yz_id');
+            pair.value = new Buffer('1*ssh-sessions*ssh-sessions*4e05ed89-2a49-4f17-8885-ca79f0d292c0*41');
+            doc.fields.push(pair);
+
+            pair = new RpbPair();
+            pair.key = new Buffer('_yz_rk');
+            pair.value = new Buffer('4e05ed89-2a49-4f17-8885-ca79f0d292c0');
+            doc.fields.push(pair);
+
+            pair = new RpbPair();
+            pair.key = new Buffer('_yz_rt');
+            pair.value = new Buffer('ssh-sessions');
+            doc.fields.push(pair);
+
+            pair = new RpbPair();
+            pair.key = new Buffer('_yz_rb');
+            pair.value = new Buffer('ssh-sessions');
+            doc.fields.push(pair);
+
+            resp.docs.push(doc);
+            resp.max_score = 1.123;
+            resp.num_found = 1;
+
+            var callback = function(err, response) {
+                assert.equal(response.numFound, 1);
+                assert.equal(response.maxScore, 1.123);
+                assert.equal(response.docs.length, 1);
+                var doc = response.docs[0];
+                assert.strictEqual(doc.state, 'connected');
+                assert.strictEqual(doc.hardwareId, 2);
+                assert.strictEqual(doc.booleanValue, true);
+                assert.strictEqual(doc._yz_id, '1*ssh-sessions*ssh-sessions*4e05ed89-2a49-4f17-8885-ca79f0d292c0*41');
+                assert.strictEqual(doc._yz_rk, '4e05ed89-2a49-4f17-8885-ca79f0d292c0');
+                assert.strictEqual(doc._yz_rt, 'ssh-sessions');
+                assert.strictEqual(doc._yz_rb, 'ssh-sessions');
+                done();
+            };
+
+            var search = new Search.Builder()
+                    .withIndexName('indexName')
+                    .withQuery('some solr query')
+                    .withConvertDocuments(true)
+                    .withCallback(callback)
+                    .build();
+            search.onSuccess(resp);
+        });
+
         it ('processes-RpbErrorResp', function(done) {
            var rpbErrorResp = new RpbErrorResp();
            rpbErrorResp.setErrmsg(new Buffer('this is an error'));