function docModule()

in lib/nano.js [638:1237]


  function docModule (dbName) {
    let docScope = {}
    dbName = decodeURIComponent(dbName)

    // http://docs.couchdb.org/en/latest/api/document/common.html#put--db-docid
    // http://docs.couchdb.org/en/latest/api/database/common.html#post--db
    function insertDoc (doc, qs0, callback0) {
      const req = { db: dbName, body: doc, method: 'POST' }

      let { opts, callback } = getCallback(qs0, callback0)

      if (typeof opts === 'string') {
        opts = { docName: opts }
      }

      if (opts) {
        if (opts.docName) {
          req.doc = opts.docName
          req.method = 'PUT'
          delete opts.docName
        }
        req.qs = opts
      }

      return relax(req, callback)
    }

    // http://docs.couchdb.org/en/latest/api/document/common.html#delete--db-docid
    function destroyDoc (docName, rev, callback) {
      if (missing(docName)) {
        return callbackOrRejectError(callback)
      }

      return relax({
        db: dbName,
        doc: docName,
        method: 'DELETE',
        qs: { rev }
      }, callback)
    }

    // http://docs.couchdb.org/en/latest/api/document/common.html#get--db-docid
    function getDoc (docName, qs0, callback0) {
      const { opts, callback } = getCallback(qs0, callback0)

      if (missing(docName)) {
        return callbackOrRejectError(callback)
      }

      return relax({ db: dbName, doc: docName, qs: opts }, callback)
    }

    // http://docs.couchdb.org/en/latest/api/document/common.html#head--db-docid
    function headDoc (docName, callback) {
      if (missing(docName)) {
        return callbackOrRejectError(callback)
      }
      if (callback) {
        relax({
          db: dbName,
          doc: docName,
          method: 'HEAD',
          qs: {}
        }, callback)
      } else {
        // this function doesn't pass on the Promise from relax because it needs
        // to return the headers when resolving the Promise
        return new Promise(function (resolve, reject) {
          relax({
            db: dbName,
            doc: docName,
            method: 'HEAD',
            qs: {}
          }, function (err, body, headers) {
            if (err) {
              reject(err)
            } else {
              resolve(headers)
            }
          })
        })
      }
    }

    // http://docs.couchdb.org/en/latest/api/database/bulk-api.html#get--db-_all_docs
    function listDoc (qs0, callback0) {
      const { opts, callback } = getCallback(qs0, callback0)
      return relax({ db: dbName, path: '_all_docs', qs: opts }, callback)
    }

    // http://docs.couchdb.org/en/latest/api/database/bulk-api.html#get--db-_all_docs
    function listDocAsStream (opts) {
      return relax({ db: dbName, path: '_all_docs', qs: opts, stream: true })
    }

    // http://docs.couchdb.org/en/latest/api/database/bulk-api.html#post--db-_all_docs
    function fetchDocs (docNames, qs0, callback0) {
      const { opts, callback } = getCallback(qs0, callback0)
      opts.include_docs = true

      if (missing(docNames) || typeof docNames !== 'object' ||
          !docNames.keys || !Array.isArray(docNames.keys) ||
          docNames.keys.length === 0) {
        return callbackOrRejectError(callback)
      }

      return relax({
        db: dbName,
        path: '_all_docs',
        method: 'POST',
        qs: opts,
        body: docNames
      }, callback)
    }

    function fetchRevs (docNames, qs0, callback0) {
      const { opts, callback } = getCallback(qs0, callback0)

      if (missing(docNames) || typeof docNames !== 'object' ||
          !docNames.keys || !Array.isArray(docNames.keys) ||
          docNames.keys.length === 0) {
        return callbackOrRejectError(callback)
      }

      return relax({
        db: dbName,
        path: '_all_docs',
        method: 'POST',
        qs: opts,
        body: docNames
      }, callback)
    }

    function view (ddoc, viewName, meta, qs0, callback0) {
      const { opts, callback } = getCallback(qs0, callback0)

      if (missing(ddoc, viewName) && !meta.viewPath) {
        return callbackOrRejectError(callback)
      }

      if (typeof meta.stream !== 'boolean') {
        meta.stream = false
      }

      // prevent mutation of the client qs object by using a clone
      const qs1 = Object.assign({}, opts)

      const viewPath = meta.viewPath || '_design/' + ddoc + '/_' + meta.type +
            '/' + viewName

      if (meta.type === 'search') {
        return relax({
          db: dbName,
          path: viewPath,
          method: 'POST',
          body: qs1,
          stream: meta.stream
        }, callback)
      } else if (qs1 && qs1.keys) {
        const body = { keys: qs1.keys }
        delete qs1.keys
        return relax({
          db: dbName,
          path: viewPath,
          method: 'POST',
          qs: qs1,
          body,
          stream: meta.stream
        }, callback)
      } else if (qs1 && qs1.queries) {
        const body = { queries: qs1.queries }
        delete qs1.queries
        return relax({
          db: dbName,
          path: viewPath,
          method: 'POST',
          qs: qs1,
          body
        }, callback)
      } else {
        const req = {
          db: dbName,
          method: meta.method || 'GET',
          path: viewPath,
          qs: qs1,
          stream: meta.stream
        }

        if (meta.body) {
          req.body = meta.body
        }

        return relax(req, callback)
      }
    }

    // http://docs.couchdb.org/en/latest/api/ddoc/views.html#post--db-_design-ddoc-_view-view
    function viewDocs (ddoc, viewName, qs, callback) {
      return view(ddoc, viewName, { type: 'view' }, qs, callback)
    }

    // http://docs.couchdb.org/en/latest/api/ddoc/views.html#post--db-_design-ddoc-_view-view
    function viewDocsAsStream (ddoc, viewName, qs) {
      return view(ddoc, viewName, { type: 'view', stream: true }, qs)
    }

    // cloudant
    function viewSearch (ddoc, viewName, qs, callback) {
      return view(ddoc, viewName, { type: 'search' }, qs, callback)
    }

    // cloudant
    function viewSearchAsStream (ddoc, viewName, qs) {
      return view(ddoc, viewName, { type: 'search', stream: true }, qs)
    }

    // http://docs.couchdb.org/en/latest/api/ddoc/render.html#get--db-_design-ddoc-_show-func
    function showDoc (ddoc, viewName, docName, qs, callback) {
      if (missing(ddoc, viewName, docName)) {
        return callbackOrRejectError(callback)
      }

      return view(ddoc, viewName + '/' + docName, { type: 'show' }, qs, callback)
    }

    // http://docs.couchdb.org/en/latest/api/ddoc/render.html#put--db-_design-ddoc-_update-func-docid
    function updateWithHandler (ddoc, viewName, docName, body, callback) {
      if (typeof body === 'function') {
        callback = body
        body = undefined
      }
      if (missing(ddoc, viewName, docName)) {
        return callbackOrRejectError(callback)
      }
      return view(ddoc, viewName + '/' + encodeURIComponent(docName), {
        type: 'update',
        method: 'PUT',
        body
      }, callback)
    }

    function viewWithList (ddoc, viewName, listName, qs, callback) {
      return view(ddoc, listName + '/' + viewName, {
        type: 'list'
      }, qs, callback)
    }

    function viewWithListAsStream (ddoc, viewName, listName, qs, callback) {
      return view(ddoc, listName + '/' + viewName, {
        type: 'list', stream: true
      }, qs, callback)
    }

    // http://docs.couchdb.org/en/latest/api/database/bulk-api.html#post--db-_bulksDoc
    function bulksDoc (docs, qs0, callback0) {
      const { opts, callback } = getCallback(qs0, callback0)
      return relax({
        db: dbName,
        path: '_bulk_docs',
        body: docs,
        method: 'POST',
        qs: opts
      }, callback)
    }

    // http://docs.couchdb.org/en/latest/api/document/common.html#creating-multiple-attachments
    function insertMultipart (doc, attachments, qs, callback) {
      if (typeof qs === 'string') {
        qs = { docName: qs }
      }
      qs = qs || {}

      const docName = qs.docName
      delete qs.docName

      if (missing(doc, attachments, docName)) {
        return callbackOrRejectError(callback)
      }

      doc = Object.assign({ _attachments: {} }, doc)

      const multipart = []

      attachments.forEach(function (att) {
        doc._attachments[att.name] = {
          follows: true,
          length: Buffer.isBuffer(att.data) ? att.data.length : Buffer.byteLength(att.data),
          /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
          content_type: att.content_type
        }
        multipart.push(att)
      })

      multipart.unshift({
        content_type: 'application/json',
        data: JSON.stringify(doc),
        name: 'document'
      })

      return relax({
        db: dbName,
        method: 'PUT',
        contentType: 'multipart/related',
        doc: docName,
        qs,
        multipart
      }, callback)
    }

    function getMultipart (docName, qs0, callback0) {
      const { opts, callback } = getCallback(qs0, callback0)
      opts.attachments = true

      if (missing(docName)) {
        return callbackOrRejectError(callback)
      }

      return relax({
        db: dbName,
        doc: docName,
        encoding: null,
        accept: 'multipart/related',
        qs: opts
      }, callback)
    }

    function insertAtt (docName, attName, att, contentType, qs0, callback0) {
      const { opts, callback } = getCallback(qs0, callback0)
      if (missing(docName, attName, att, contentType)) {
        return callbackOrRejectError(callback)
      }

      return relax({
        db: dbName,
        att: attName,
        method: 'PUT',
        contentType,
        doc: docName,
        qs: opts,
        body: att,
        dontStringify: true
      }, callback)
    }

    function getAtt (docName, attName, qs0, callback0) {
      const { opts, callback } = getCallback(qs0, callback0)

      if (missing(docName, attName)) {
        return callbackOrRejectError(callback)
      }

      return relax({
        db: dbName,
        att: attName,
        doc: docName,
        qs: opts,
        encoding: null,
        dontParse: true
      }, callback)
    }

    function getAttAsStream (docName, attName, opts) {
      return relax({
        db: dbName,
        att: attName,
        doc: docName,
        qs: opts,
        stream: true,
        encoding: null,
        dontParse: true
      })
    }

    function destroyAtt (docName, attName, qs, callback) {
      if (missing(docName, attName)) {
        return callbackOrRejectError(callback)
      }

      return relax({
        db: dbName,
        att: attName,
        method: 'DELETE',
        doc: docName,
        qs
      }, callback)
    }

    function find (query, callback) {
      if (missing(query) || typeof query !== 'object') {
        return callbackOrRejectError(callback)
      }

      return relax({
        db: dbName,
        path: '_find',
        method: 'POST',
        body: query
      }, callback)
    }

    function findAsStream (query) {
      return relax({
        db: dbName,
        path: '_find',
        method: 'POST',
        body: query,
        stream: true
      })
    }

    function createIndex (indexDef, callback) {
      if (missing(indexDef) || typeof indexDef !== 'object') {
        return callbackOrRejectError(callback)
      }

      return relax({
        db: dbName,
        path: '_index',
        method: 'POST',
        body: indexDef
      }, callback)
    }

    function partitionInfo (partitionKey, callback) {
      if (missing(partitionKey)) {
        return callbackOrRejectError(callback)
      }

      return relax({
        db: dbName,
        path: '_partition/' + encodeURIComponent(partitionKey)
      }, callback)
    }

    function partitionedList (partitionKey, qs0, callback0) {
      const { opts, callback } = getCallback(qs0, callback0)
      if (missing(partitionKey)) {
        return callbackOrRejectError(callback)
      }
      return relax({
        db: dbName,
        path: '_partition/' + encodeURIComponent(partitionKey) + '/_all_docs',
        qs: opts
      }, callback)
    }

    function partitionedListAsStream (partitionKey, qs) {
      return relax({
        db: dbName,
        path: '_partition/' + encodeURIComponent(partitionKey) + '/_all_docs',
        qs,
        stream: true
      })
    }

    function partitionedFind (partition, query, callback) {
      if (missing(partition, query) || typeof query !== 'object') {
        return callbackOrRejectError(callback)
      }

      return relax({
        db: dbName,
        path: '_partition/' + encodeURIComponent(partition) + '/_find',
        method: 'POST',
        body: query
      }, callback)
    }

    function partitionedFindAsStream (partition, query) {
      return relax({
        db: dbName,
        path: '_partition/' + encodeURIComponent(partition) + '/_find',
        method: 'POST',
        body: query,
        stream: true
      })
    }

    function partitionedSearch (partition, ddoc, searchName, opts, callback) {
      if (missing(partition, ddoc, searchName, opts) || typeof opts !== 'object') {
        return callbackOrRejectError(callback)
      }
      return relax({
        db: dbName,
        path: '_partition/' + encodeURIComponent(partition) + '/_design/' + ddoc + '/_search/' + searchName,
        qs: opts
      }, callback)
    }

    function partitionedSearchAsStream (partition, ddoc, searchName, opts) {
      return relax({
        db: dbName,
        path: '_partition/' + encodeURIComponent(partition) + '/_design/' + ddoc + '/_search/' + searchName,
        qs: opts,
        stream: true
      })
    }

    function partitionedView (partition, ddoc, viewName, opts, callback) {
      if (missing(partition, ddoc, viewName)) {
        return callbackOrRejectError(callback)
      }
      return relax({
        db: dbName,
        path: '_partition/' + encodeURIComponent(partition) + '/_design/' + ddoc + '/_view/' + viewName,
        qs: opts
      }, callback)
    }

    function partitionedViewAsStream (partition, ddoc, viewName, opts) {
      return relax({
        db: dbName,
        path: '_partition/' + encodeURIComponent(partition) + '/_design/' + ddoc + '/_view/' + viewName,
        qs: opts,
        stream: true
      })
    }

    // db level exports
    docScope = {
      info: function (cb) {
        return getDb(dbName, cb)
      },
      replicate: function (target, opts, cb) {
        return replicateDb(dbName, target, opts, cb)
      },
      compact: function (cb) {
        return compactDb(dbName, cb)
      },
      changes: function (qs, cb) {
        return changesDb(dbName, qs, cb)
      },
      changesAsStream: function (qs) {
        return changesDbAsStream(dbName, qs)
      },
      changesReader: new ChangesReader(dbName, relax),
      auth,
      session,
      insert: insertDoc,
      get: getDoc,
      head: headDoc,
      destroy: destroyDoc,
      bulk: bulksDoc,
      list: listDoc,
      listAsStream: listDocAsStream,
      fetch: fetchDocs,
      fetchRevs,
      config: { url: cfg.url, db: dbName },
      multipart: {
        insert: insertMultipart,
        get: getMultipart
      },
      attachment: {
        insert: insertAtt,
        get: getAtt,
        getAsStream: getAttAsStream,
        destroy: destroyAtt
      },
      show: showDoc,
      atomic: updateWithHandler,
      updateWithHandler,
      baseView: view,
      search: viewSearch,
      searchAsStream: viewSearchAsStream,
      view: viewDocs,
      viewAsStream: viewDocsAsStream,
      find,
      findAsStream,
      createIndex,
      viewWithList,
      viewWithListAsStream,
      server: serverScope,
      replication: {
        enable: function (target, opts, cb) {
          return enableReplication(dbName, target, opts, cb)
        },
        disable: function (id, revision, opts, cb) {
          return disableReplication(id, revision, opts, cb)
        },
        query: function (id, opts, cb) {
          return queryReplication(id, opts, cb)
        }
      },
      partitionInfo,
      partitionedList,
      partitionedListAsStream,
      partitionedFind,
      partitionedFindAsStream,
      partitionedSearch,
      partitionedSearchAsStream,
      partitionedView,
      partitionedViewAsStream
    }

    docScope.view.compact = function (ddoc, cb) {
      return compactDb(dbName, ddoc, cb)
    }

    return docScope
  }