<commit_before>const Programs = require('./program')
const Systems = require('./system')
const Issuers = require('./issuer')
const db = require('../lib/db');
const makeValidator = require('../lib/make-validator')

const Badges = db.table('badges', {
  fields: [
    'id',
    'slug',
    'name',
    'strapline',
    'description',
    'archived',
    'imageId',
    'systemId',
    'issuerId',
    'programId',
  ],
  relationships: {
    image: {
      type: 'hasOne',
      local: 'imageId',
      foreign: { table: 'images', key: 'id' },
      optional: true
    },
    system: {
      type: 'hasOne',
      local: 'systemId',
      foreign: { table: 'systems', key: 'id' },
      optional: true,
    },
    issuer: {
      type: 'hasOne',
      local: 'issuerId',
      foreign: { table: 'issuers', key: 'id' },
      optional: true,
    },
    program: {
      type: 'hasOne',
      local: 'programId',
      foreign: { table: 'programs', key: 'id' },
      optional: true,
    },
  }
});

Badges.getByProgram = function getByProgram(programSlug, callback) {
  Programs.getOne({slug: programSlug}, function (err, program) {
    if (err) return callback(err)
    if (!program) return callback()
    const query = {programId: program.id}
    const opts = {relationships: true}
    Badges.get(query, opts, callback)
  })
}

Badges.getByIssuer = function getByIssuer(issuerSlug, callback) {
  // should include all program badges as well
  const query = {slug: issuerSlug}
  const opts = {relationships: true}
  Issuers.getOne(query, opts, function (err, issuer) {
    if (err) return callback(err)
    if (!issuer) return callback()

    const programIds = issuer.programs.map(function (o) { return o.id })

    const query = {issuerId: issuer.id}
    const opts = {relationships: true}
    Badges.get(query, opts, function (err, issuerBadges) {
      if (err) return callback(err)

      const query = {programId: programIds}
      const opts = {relationships: true}
      Badges.get(query, opts, function (err, programBadges) {
        if (err) return callback(err)

        const allBadges = issuerBadges.concat(programBadges)
        return callback(null, allBadges)
      })
    })
  })
}

Badges.validateRow = makeValidator({
  id: optionalInt,
  slug: function (slug) {
    this.check(slug).len(1, 50);
  },
  name: function (name) {
    this.check(name).len(1, 255);
  },
  strapline: function (text) {
    this.check(text).len(0, 50);
  },
  description: function (desc) {
    this.check(desc).len(1, 255);
  },
  imageId: optionalInt,
  programId: optionalInt,
  issuerId: optionalInt,
  systemId: optionalInt,
});

function optionalInt(id) {
  if (typeof id == 'undefined' || id === null) return;
  this.check(id).isInt();
}

exports = module.exports = Badges;<commit_msg>Factor out map function `value`.<commit_after>const Programs = require('./program')
const Systems = require('./system')
const Issuers = require('./issuer')
const db = require('../lib/db');
const makeValidator = require('../lib/make-validator')

const Badges = db.table('badges', {
  fields: [
    'id',
    'slug',
    'name',
    'strapline',
    'description',
    'archived',
    'imageId',
    'systemId',
    'issuerId',
    'programId',
  ],
  relationships: {
    image: {
      type: 'hasOne',
      local: 'imageId',
      foreign: { table: 'images', key: 'id' },
      optional: true
    },
    system: {
      type: 'hasOne',
      local: 'systemId',
      foreign: { table: 'systems', key: 'id' },
      optional: true,
    },
    issuer: {
      type: 'hasOne',
      local: 'issuerId',
      foreign: { table: 'issuers', key: 'id' },
      optional: true,
    },
    program: {
      type: 'hasOne',
      local: 'programId',
      foreign: { table: 'programs', key: 'id' },
      optional: true,
    },
  }
});

Badges.getByProgram = function getByProgram(programSlug, callback) {
  Programs.getOne({slug: programSlug}, function (err, program) {
    if (err) return callback(err)
    if (!program) return callback()
    const query = {programId: program.id}
    const opts = {relationships: true}
    Badges.get(query, opts, callback)
  })
}

Badges.getByIssuer = function getByIssuer(issuerSlug, callback) {
  // should include all program badges as well
  const query = {slug: issuerSlug}
  const opts = {relationships: true}
  Issuers.getOne(query, opts, function (err, issuer) {
    if (err) return callback(err)
    if (!issuer) return callback()

    const programIds = issuer.programs.map(value('id'))

    const query = {issuerId: issuer.id}
    const opts = {relationships: true}
    // TODO: this can be parallelized
    Badges.get(query, opts, function (err, issuerBadges) {
      if (err) return callback(err)
      const query = {programId: programIds}
      const opts = {relationships: true}
      Badges.get(query, opts, function (err, programBadges) {
        if (err) return callback(err)
        const allBadges = issuerBadges.concat(programBadges)
        return callback(null, allBadges)
      })
    })
  })
}

Badges.validateRow = makeValidator({
  id: optionalInt,
  slug: function (slug) {
    this.check(slug).len(1, 50);
  },
  name: function (name) {
    this.check(name).len(1, 255);
  },
  strapline: function (text) {
    this.check(text).len(0, 50);
  },
  description: function (desc) {
    this.check(desc).len(1, 255);
  },
  imageId: optionalInt,
  programId: optionalInt,
  issuerId: optionalInt,
  systemId: optionalInt,
});

function optionalInt(id) {
  if (typeof id == 'undefined' || id === null) return;
  this.check(id).isInt();
}

function value(name) {
  return function (obj) {
    return obj[name]
  }
}

exports = module.exports = Badges;
{'fraction_non_alphanumeric': 0.15385967997186567, 'fraction_numerical': 0.004923509759099701, 'mean_word_length': 3.028328611898017, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '4366493', 'n_tokens_mistral': 1931, 'n_tokens_neox': 1909, 'n_words': 470}