<commit_before>'use strict'

const RBAC = require('easy-rbac')
const MongoClient = require('mongodb').MongoClient
const errors = require('lambda-errors-formatter')
const options = require('./options')

function rbacCatch(err, callback) {
  if (err && typeof err.message === 'string') {
    return callback(errors.forbidden(err.message))
  }
  return callback(errors.internalServerError())
}

class Crud {

  constructor(stringConnection, collectionName, user, roles) {
    this.stringConnection = stringConnection
    this.collectionName = collectionName
    this.user = user
    this.rbac = new RBAC(roles)
  }

  list(query, permission, roleOptions, callback) {

    const pagination = options.getPagination(query);
    const sort = options.getSort(query);
    const search = options.getSearch(query);
    const projections = options.getProjections(query);

    query = options.clearQuery(query)
    query = Object.assign(query, search);

    this.rbac.can(this.user.role, permission, roleOptions)

      .then(() => {

        MongoClient.connect(this.stringConnection, (err, db) => {

          if (err) {
            return callback(err)
          }

          let collection = db.collection(this.collectionName)

          collection.find(query).sort(sort).project(projections).limit(pagination.limit).skip(pagination.from).toArray((err, docs) => {

            if (err) {
              db.close()
              return callback(err)
            }

            if (!pagination.isPaginated) {
              db.close()
              return callback(null, docs)
            }

            collection.count(query, (err, total) => {
              db.close()

              if (err) {
                return callback(err)
              }

              return callback(null, options.getPaginatedResponse(docs, pagination, total))
            });
          })
        })
      })

      .catch(err => rbacCatch(err, callback))
  }

  listAggregate(query, stages, permission, roleOptions, callback) {

    this.rbac.can(this.user.role, permission, roleOptions)

      .then(() => {

        MongoClient.connect(this.stringConnection, (err, db) => {

          if (err) {
            return callback(err)
          }

          const pagination = options.getPagination(query);
          const sort = options.getSort(query);
          const search = options.getSearch(query);
          const projections = options.getProjections(query);

          query = options.clearQuery(query)
          query = Object.assign(query, search);

          let collection = db.collection(this.collectionName)
          collection.count(query, (err, total) => {

            if (err) {
              db.close()
              return callback(err)
            }

            stages.unshift({ $match: query })

            if (sort && Object.keys(sort).length > 0) {
              stages.push({ $sort: sort })
            }

            if (projections && Object.keys(projections).length > 0) {
              stages.push({ $project: projections })
            }

            stages = stages.concat(options.getPaginationStages(pagination));

            collection.aggregate(stages, (err, results) => {

              db.close()

              if (err) {
                return callback(err)
              }<commit_msg>fix (listAggregate): cursor for mongodb-3.6 compatibility<commit_after>'use strict'

const RBAC = require('easy-rbac')
const MongoClient = require('mongodb').MongoClient
const errors = require('lambda-errors-formatter')
const options = require('./options')

function rbacCatch(err, callback) {
  if (err && typeof err.message === 'string') {
    return callback(errors.forbidden(err.message))
  }
  return callback(errors.internalServerError())
}

class Crud {

  constructor(stringConnection, collectionName, user, roles) {
    this.stringConnection = stringConnection
    this.collectionName = collectionName
    this.user = user
    this.rbac = new RBAC(roles)
  }

  list(query, permission, roleOptions, callback) {

    const pagination = options.getPagination(query);
    const sort = options.getSort(query);
    const search = options.getSearch(query);
    const projections = options.getProjections(query);

    query = options.clearQuery(query)
    query = Object.assign(query, search);

    this.rbac.can(this.user.role, permission, roleOptions)

      .then(() => {

        MongoClient.connect(this.stringConnection, (err, db) => {

          if (err) {
            return callback(err)
          }

          let collection = db.collection(this.collectionName)

          collection.find(query).sort(sort).project(projections).limit(pagination.limit).skip(pagination.from).toArray((err, docs) => {

            if (err) {
              db.close()
              return callback(err)
            }

            if (!pagination.isPaginated) {
              db.close()
              return callback(null, docs)
            }

            collection.count(query, (err, total) => {
              db.close()

              if (err) {
                return callback(err)
              }

              return callback(null, options.getPaginatedResponse(docs, pagination, total))
            });
          })
        })
      })

      .catch(err => rbacCatch(err, callback))
  }

  listAggregate(query, stages, permission, roleOptions, callback) {

    this.rbac.can(this.user.role, permission, roleOptions)

      .then(() => {

        MongoClient.connect(this.stringConnection, (err, db) => {

          if (err) {
            return callback(err)
          }

          const pagination = options.getPagination(query);
          const sort = options.getSort(query);
          const search = options.getSearch(query);
          const projections = options.getProjections(query);

          query = options.clearQuery(query)
          query = Object.assign(query, search);

          let collection = db.collection(this.collectionName)
          collection.count(query, (err, total) => {

            if (err) {
              db.close()
              return callback(err)
            }

            stages.unshift({ $match: query })

            if (sort && Object.keys(sort).length > 0) {
              stages.push({ $sort: sort })
            }

            if (projections && Object.keys(projections).length > 0) {
              stages.push({ $project: projections })
            }

            stages = stages.concat(options.getPaginationStages(pagination));

            collection
              .aggregate(stages, { cursor: { batchSize: 1 }})
              .toArray((err, results) => {

              db.close()

              if (err) {
                return callback(err)
              }
{'fraction_non_alphanumeric': 0.12124832014334777, 'fraction_numerical': 0.001045244139166791, 'mean_word_length': 2.0528714676390156, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5340713', 'n_tokens_mistral': 1870, 'n_tokens_neox': 1793, 'n_words': 361}