docs: function(key, options, callback){
      var self = this;
      //var layer = 0;
      var error = false,
        totalLayers,
        queryOpts = {},
        allLayers = [];
  
      // closure to check each layer and send back when done
      var collect = function(err, data){
        if (err) error = err;
        allLayers.push(data);
        if (allLayers.length == totalLayers){
          callback(error, allLayers);
        }
      };
  
      this._query('select info from "'+this.infoTable+'" where id=\''+(key+':'+(options.layer || 0 )+":info")+'\'', function(err, rows){
        if ( err || !rows || !rows.length ){
          callback('Not Found', []);
        } else if (rows[0].info.status == 'processing' && !options.bypassProcessing ) {
          callback( null, [{ status: 'processing' }]);
        } else {
            var info = JSON.parse(rows[0].info);
            var select = 'select feature from "' + key+':'+(options.layer || 0)+'"';
  
            // parse the where clause
            if ( options.where && options.where != '1=1'){
              var where = sql.parse( 'select * from foo where '+ options.where).where;
              select = self.parseWhere( select, where);
            }
  
            // parse the geometry param from GeoServices REST
            if ( options.geometry ){
  
              if ( typeof(options.geometry) == 'string' ){
                try {
                  options.geometry = JSON.parse( options.geometry );
                } catch(e){
                  console.log('Error parsing options.geometry', options.geometry);
                  try {
                    if ( options.geometry.split(',').length == 4 ){
                      var extent = options.geometry.split(',');
                      options.geometry = { spatialReference: {wkid: 4326} };
                      options.geometry.xmin = extent[0];
                      options.geometry.ymin = extent[1];
                      options.geometry.xmax = extent[2];
                      options.geometry.ymax = extent[3];
                    }
                  } catch(ex){
                    console.log('Error building bbox from', options.geometry);
                  }
                }
              }
  
              if (options.geometry.xmin && options.geometry.ymin ){
                var box = options.geometry;
                if (box.spatialReference.wkid != 4326){
                  var mins = merc.inverse( [box.xmin, box.ymin] ),
                    maxs = merc.inverse( [box.xmax, box.ymax] );
                  box.xmin = mins[0];
                  box.ymin = mins[1];
                  box.xmax = maxs[0];
                  box.ymax = maxs[1];
                }
  
                select += (options.where ) ? ' AND ' : ' WHERE ';
                select += 'ST_Intersects(ST_GeomFromGeoJSON(feature->>\'geometry\'), ST_MakeEnvelope('+box.xmin+','+box.ymin+','+box.xmax+','+box.ymax+'))';
              }
            }
  
            if ( options.limit ) {
              select += ' LIMIT ' + options.limit;
            }
  
            //console.log(select);
            self._query( select, function (err, rows) {
              if ( rows && rows.length ) {
                callback( null, [{
                  type: 'FeatureCollection',
                  features: _.map(_.pluck(rows, 'feature'), function(jsonStr) { return JSON.parse(jsonStr); }),
                  name: info.name,
                  sha: info.sha,
                  info: info.info,
                  updated_at: info.updated_at
                }]);
              } else {
                callback( 'Not Found', [{
                  type: 'FeatureCollection',
                  features: []
                }]);
              }
            });
          }
      });
    }