<commit_before>import applyPagination from './util/applyPagination'
import presentQuerySet from './util/presentQuerySet'
import initDataLoaders from './util/initDataLoaders'
import { isNull, isUndefined, omitBy, result, toPairs } from 'lodash/fp'

export default class Fetcher {
  constructor (models, options = {}) {
    this.models = models

    // here we allow changing loader behavior to make testing easier
    const setupLoaders = options.setupLoaders || initDataLoaders
    this.loaders = setupLoaders(models)
  }

  fetchRelation (relation, typename, fetchOpts, tap) {
    let targetTableName, type, parentFk
    if (relation.relatedData) {
      targetTableName = relation.relatedData.targetTableName
      type = relation.relatedData.type
      parentFk = relation.relatedData.parentFk
    } else {
      // this is a hack to allow relations that are not "proper" bookshelf
      // relations, i.e. they don't use Model#hasMany() et al. it seems that
      // we could go much further and merge getters and relations into a single
      // concept in the graphql-bookshelf-bridge model spec language. TBD.
      targetTableName = relation.tableName()
      type = 'hasMany' // n.b. we're not supporting belongsTo yet
    }

    if (!typename) typename = this._getTypenameFromTableName(targetTableName)
    const loader = this.loaders[typename]

    if (type === 'belongsTo') {
      if (!parentFk) return Promise.resolve()
      return loader.load(parentFk)
    }

    // apply the filter that always applies to this target model, if any
    const model = this._getModel(typename)
    if (model.filter) relation = model.filter(relation)

    // apply the filter that applies to this specific pair of models, if any
    if (fetchOpts.filter) relation = fetchOpts.filter(relation)

    if (type === 'hasOne') {
      return this._loadOne(relation, { loader })
    }

    const query = relation.query(q => {
      applyPagination(q, targetTableName, fetchOpts)
    })

    return this._loadMany(query, {loader, fetchOpts, tap})
  }

  fetchOne (typename, id, idColumn = 'id') {
    if (!id) return Promise.resolve(null)

    const { model, filter } = this._getModel(typename)
    let relation = model.where(idColumn, id)
    if (filter) relation = filter(relation)
    return this.loaders.relations.load({relation}).then(instance => {
      if (!instance) return
      this.loaders[typename].prime(instance.id, instance)
      return instance<commit_msg>disambiguate id column in fetchOne<commit_after>import applyPagination from './util/applyPagination'
import presentQuerySet from './util/presentQuerySet'
import initDataLoaders from './util/initDataLoaders'
import { isNull, isUndefined, omitBy, result, toPairs } from 'lodash/fp'

export default class Fetcher {
  constructor (models, options = {}) {
    this.models = models

    // here we allow changing loader behavior to make testing easier
    const setupLoaders = options.setupLoaders || initDataLoaders
    this.loaders = setupLoaders(models)
  }

  fetchRelation (relation, typename, fetchOpts, tap) {
    let targetTableName, type, parentFk
    if (relation.relatedData) {
      targetTableName = relation.relatedData.targetTableName
      type = relation.relatedData.type
      parentFk = relation.relatedData.parentFk
    } else {
      // this is a hack to allow relations that are not "proper" bookshelf
      // relations, i.e. they don't use Model#hasMany() et al. it seems that
      // we could go much further and merge getters and relations into a single
      // concept in the graphql-bookshelf-bridge model spec language. TBD.
      targetTableName = relation.tableName()
      type = 'hasMany' // n.b. we're not supporting belongsTo yet
    }

    if (!typename) typename = this._getTypenameFromTableName(targetTableName)
    const loader = this.loaders[typename]

    if (type === 'belongsTo') {
      if (!parentFk) return Promise.resolve()
      return loader.load(parentFk)
    }

    // apply the filter that always applies to this target model, if any
    const model = this._getModel(typename)
    if (model.filter) relation = model.filter(relation)

    // apply the filter that applies to this specific pair of models, if any
    if (fetchOpts.filter) relation = fetchOpts.filter(relation)

    if (type === 'hasOne') {
      return this._loadOne(relation, { loader })
    }

    const query = relation.query(q => {
      applyPagination(q, targetTableName, fetchOpts)
    })

    return this._loadMany(query, {loader, fetchOpts, tap})
  }

  fetchOne (typename, id, idColumn = 'id') {
    if (!id) return Promise.resolve(null)

    const { model, filter } = this._getModel(typename)
    const tableName = model.collection().tableName()
    let relation = model.where(`${tableName}.${idColumn}`, id)
    if (filter) relation = filter(relation)
    return this.loaders.relations.load({relation}).then(instance => {
      if (!instance) return
      this.loaders[typename].prime(instance.id, instance)
      return instance
{'fraction_non_alphanumeric': 0.10247208931419458, 'fraction_numerical': 0.0, 'mean_word_length': 3.3778359511343803, 'pattern_counts': {'":': 0, '<': 3, '<?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': '7136070', 'n_tokens_mistral': 1443, 'n_tokens_neox': 1418, 'n_words': 438}