<commit_before>var express = require('express')
var _ = require('lodash')
var pluralize = require('pluralize')
var utils = require('../utils')

module.exports = function (db, name) {
  // Create router
  var router = express.Router()

  // Embed function used in GET /name and GET /name/id
  function embed (resource, e) {
    e && [].concat(e)
      .forEach(function (externalResource) {
        if (db.get(externalResource).value) {
          var query = {}
          var singularResource = pluralize.singular(name)
          query[singularResource + 'Id'] = resource.id
          resource[externalResource] = db.get(externalResource).filter(query).value()
        }
      })
  }

  // Expand function used in GET /name and GET /name/id
  function expand (resource, e) {
    e && [].concat(e)
      .forEach(function (innerResource) {
        var plural = pluralize(innerResource)
        if (db.get(plural).value()) {
          var prop = innerResource + 'Id'
          resource[innerResource] = db.get(plural).getById(resource[prop]).value()
        }
      })
  }

  function getFullURL (req) {
    return req.protocol + '://' + req.get('host') + req.originalUrl
  }

  // GET /name
  // GET /name?q=
  // GET /name?attr=&attr=
  // GET /name?_end=&
  // GET /name?_start=&_end=&
  // GET /name?_embed=&_expand=
  function list (req, res, next) {
    // Resource chain
    var chain = db.get(name)

    // Remove q, _start, _end, ... from req.query to avoid filtering using those
    // parameters
    var q = req.query.q
    var _start = req.query._start
    var _end = req.query._end
    var _page = req.query._page
    var _sort = req.query._sort
    var _order = req.query._order
    var _limit = req.query._limit
    var _embed = req.query._embed
    var _expand = req.query._expand
    delete req.query.q
    delete req.query._start
    delete req.query._end
    delete req.query._sort
    delete req.query._order
    delete req.query._limit
    delete req.query._embed
    delete req.query._expand

    // Automatically delete query parameters that can't be found
    // in the database
    Object.keys(req.query).forEach(function (query) {
      var arr = db.get(name).value()
      for (var i in arr) {
        if (
          _.has(arr[i], query) ||
          query === 'callback' ||
          query === '_' ||
          query.indexOf('_lte') !== -1 ||
          query.indexOf('_gte') !== -1 ||
          query.indexOf('_ne') !== -1 ||
          query.indexOf('_like') !== -1
        ) return
      }
      delete req.query[query]
    })

    if (q) {
      // Full-text search
      q = q.toLowerCase()

      chain = chain.filter(function (obj) {
        for (var key in obj) {
          var value = obj[key]
          if (db._.deepQuery(value, q)) {
            return true
          }
        }
      })
    }

    Object.keys(req.query).forEach(function (key) {
      // Don't take into account JSONP query parameters
      // jQuery adds a '_' query parameter too
      if (key !== 'callback' && key !== '_') {
        // Always use an array, in case req.query is an array
        var arr = [].concat(req.query[key])

        chain = chain.filter(function (element) {
          return arr
            .map(utils.toNative)
            .map(function (value) {
              var isDifferent = key.indexOf('_ne') !== -1
              var isRange = key.indexOf('_lte') !== -1 || key.indexOf('_gte') !== -1
              var isLike = key.indexOf('_like') !== -1
              var path = key.replace(/(_lte|_gte|_ne|_like)$/, '')
              var elementValue = _.get(element, path)

              if (isRange) {
                var isLowerThan = key.indexOf('_gte') !== -1

                if (isLowerThan) {
                  return value <= elementValue
                } else {
                  return value >= elementValue
                }
              } else if (isDifferent) {
                return value !== elementValue
              } else if (isLike) {
                return new RegExp(value, 'i').test(elementValue)
              } else {
                return _.matchesProperty(key, value)(element)
              }
            }).reduce(function (a, b) {
              return a || b
            })
        })
      }
    })

    // Sort
    if (_sort) {
      _order = _order || 'ASC'

      chain = chain.sortBy(function (element) {
        return _.get(element, _sort)
      })

      if (_order === 'DESC') {
        chain = chain.reverse()
      }
    }

    // Slice result
    if (_end || _limit || _page) {
      res.setHeader('X-Total-Count', chain.size())
      res.setHeader('Access-Control-Expose-Headers', 'X-Total-Count')
    }

    if (_page) {
      _page = parseInt(_page, 10)
      _page = _page >= 1 ? _page : 1
      _limit = parseInt(_limit, 10) || 10
      var page = utils.getPage(chain.value(), _page, _limit)
      var links = {}
      var fullURL = getFullURL(req)

      if (page.first) {
        links.first = fullURL.replace('page=' + page.current, 'page=' + page.first)
      }

      if (page.prev) {
        links.prev = fullURL.replace('page=' + page.current, 'page=' + page.prev)
      }

      if (page.next) {
        links.next = fullURL.replace('page=' + page.current, 'page=' + page.next)
      }

      if (page.last) {
        links.last = fullURL.replace('page=' + page.current, 'page=' + page.last)
      }

      res.links(links)
      chain = _.chain(page.items)
    } else if (_end) {
      _start = parseInt(_start, 10) || 0
      _end = parseInt(_end, 10)<commit_msg>Expose the Links header. (#381)<commit_after>var express = require('express')
var _ = require('lodash')
var pluralize = require('pluralize')
var utils = require('../utils')

module.exports = function (db, name) {
  // Create router
  var router = express.Router()

  // Embed function used in GET /name and GET /name/id
  function embed (resource, e) {
    e && [].concat(e)
      .forEach(function (externalResource) {
        if (db.get(externalResource).value) {
          var query = {}
          var singularResource = pluralize.singular(name)
          query[singularResource + 'Id'] = resource.id
          resource[externalResource] = db.get(externalResource).filter(query).value()
        }
      })
  }

  // Expand function used in GET /name and GET /name/id
  function expand (resource, e) {
    e && [].concat(e)
      .forEach(function (innerResource) {
        var plural = pluralize(innerResource)
        if (db.get(plural).value()) {
          var prop = innerResource + 'Id'
          resource[innerResource] = db.get(plural).getById(resource[prop]).value()
        }
      })
  }

  function getFullURL (req) {
    return req.protocol + '://' + req.get('host') + req.originalUrl
  }

  // GET /name
  // GET /name?q=
  // GET /name?attr=&attr=
  // GET /name?_end=&
  // GET /name?_start=&_end=&
  // GET /name?_embed=&_expand=
  function list (req, res, next) {
    // Resource chain
    var chain = db.get(name)

    // Remove q, _start, _end, ... from req.query to avoid filtering using those
    // parameters
    var q = req.query.q
    var _start = req.query._start
    var _end = req.query._end
    var _page = req.query._page
    var _sort = req.query._sort
    var _order = req.query._order
    var _limit = req.query._limit
    var _embed = req.query._embed
    var _expand = req.query._expand
    delete req.query.q
    delete req.query._start
    delete req.query._end
    delete req.query._sort
    delete req.query._order
    delete req.query._limit
    delete req.query._embed
    delete req.query._expand

    // Automatically delete query parameters that can't be found
    // in the database
    Object.keys(req.query).forEach(function (query) {
      var arr = db.get(name).value()
      for (var i in arr) {
        if (
          _.has(arr[i], query) ||
          query === 'callback' ||
          query === '_' ||
          query.indexOf('_lte') !== -1 ||
          query.indexOf('_gte') !== -1 ||
          query.indexOf('_ne') !== -1 ||
          query.indexOf('_like') !== -1
        ) return
      }
      delete req.query[query]
    })

    if (q) {
      // Full-text search
      q = q.toLowerCase()

      chain = chain.filter(function (obj) {
        for (var key in obj) {
          var value = obj[key]
          if (db._.deepQuery(value, q)) {
            return true
          }
        }
      })
    }

    Object.keys(req.query).forEach(function (key) {
      // Don't take into account JSONP query parameters
      // jQuery adds a '_' query parameter too
      if (key !== 'callback' && key !== '_') {
        // Always use an array, in case req.query is an array
        var arr = [].concat(req.query[key])

        chain = chain.filter(function (element) {
          return arr
            .map(utils.toNative)
            .map(function (value) {
              var isDifferent = key.indexOf('_ne') !== -1
              var isRange = key.indexOf('_lte') !== -1 || key.indexOf('_gte') !== -1
              var isLike = key.indexOf('_like') !== -1
              var path = key.replace(/(_lte|_gte|_ne|_like)$/, '')
              var elementValue = _.get(element, path)

              if (isRange) {
                var isLowerThan = key.indexOf('_gte') !== -1

                if (isLowerThan) {
                  return value <= elementValue
                } else {
                  return value >= elementValue
                }
              } else if (isDifferent) {
                return value !== elementValue
              } else if (isLike) {
                return new RegExp(value, 'i').test(elementValue)
              } else {
                return _.matchesProperty(key, value)(element)
              }
            }).reduce(function (a, b) {
              return a || b
            })
        })
      }
    })

    // Sort
    if (_sort) {
      _order = _order || 'ASC'

      chain = chain.sortBy(function (element) {
        return _.get(element, _sort)
      })

      if (_order === 'DESC') {
        chain = chain.reverse()
      }
    }

    // Slice result
    if (_end || _limit || _page) {
      res.setHeader('X-Total-Count', chain.size())
      res.setHeader('Access-Control-Expose-Headers', 'X-Total-Count' + (_page ? ', Links' : ''))
    }

    if (_page) {
      _page = parseInt(_page, 10)
      _page = _page >= 1 ? _page : 1
      _limit = parseInt(_limit, 10) || 10
      var page = utils.getPage(chain.value(), _page, _limit)
      var links = {}
      var fullURL = getFullURL(req)

      if (page.first) {
        links.first = fullURL.replace('page=' + page.current, 'page=' + page.first)
      }

      if (page.prev) {
        links.prev = fullURL.replace('page=' + page.current, 'page=' + page.prev)
      }

      if (page.next) {
        links.next = fullURL.replace('page=' + page.current, 'page=' + page.next)
      }

      if (page.last) {
        links.last = fullURL.replace('page=' + page.current, 'page=' + page.last)
      }

      res.links(links)
      chain = _.chain(page.items)
    } else if (_end) {
      _start = parseInt(_start, 10) || 0
      _end = parseInt(_end, 10)
{'fraction_non_alphanumeric': 0.14469078179696615, 'fraction_numerical': 0.004218651826586483, 'mean_word_length': 1.8343932841516153, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, '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': '6584216', 'n_tokens_mistral': 3466, 'n_tokens_neox': 3362, 'n_words': 829}