async function ingestSingleLocation(
  locationName,
  athleteDoc,
  { isDryRun = false },
) {
  if (!configLocations[locationName]) {
    // @todo Report error
    console.log(`Couldn't find location: ${JSON.stringify(locationName)}`);
    return false;
  }

  const {
    canonicalSegmentId,
  } = configLocations[locationName];

  try {
    const ingestor = new LocationIngest(athleteDoc, canonicalSegmentId);

    await ingestor.fetchActivities();
    console.log(`Found ${ingestor.getNumActivities()} activities`);

    if (!ingestor.getNumActivities()) {
      return false;
    }

    ingestor.prepareActivities();
    const invalidActivities = ingestor.getInvalidActivities();
    const numInvalid = invalidActivities.length;

    if (numInvalid) {
      console.log(JSON.stringify(invalidActivities, null, 2));
    }

    if (numInvalid / ingestor.getNumActivities() > MAX_INVALID_ACTIVITIES) {
      captureSentry('Exceeded max % invalid activities', 'ingestAthleteHistory', {
        level: 'warning',
        tags: { dryRun: isDryRun ? '1' : '0' },
        extra: {
          athlete: athleteDoc.id,
          numInvalid,
          activities: JSON.stringify(ingestor.getInvalidActivitiesIds()),
        },
      });
      return {};
    }

    if (!isDryRun) {
      await ingestor.saveActivities();
    }

    // Regenerates complete stats from all activities
    // but only keeps a copy of this location's stats
    ingestor.generateStats();
    if (!isDryRun) {
      // Merges this location's stats
      // back into complete stats then saves
      // Not sure why I did it this way 🤷‍♂️
      await ingestor.saveStats();
    }

    return {
      locationName,
      stats: ingestor.getStats(),
    };
  } catch (err) {
    captureSentry(err, 'ingestSingleLocation', {
      extra: {
        locationName,
        canonicalSegmentId,
        athletedId: athleteDoc.id,
      },
    });
  }
  return false;
}
/**
 * Create LocationIngest object for a given location
 * Save activities and stats depending on value of isDryRun
 *
 * @param {String} locationName
 * @param {Athlete} athleteDoc
 * @param {Boolean} opts.isDryRun
 * @returns {Object} obj.locationName
 * @returns {Object} obj.stats
 */
Create LocationIngest object for a given location
Save activities and stats depending on value of isDryRun


Create LocationIngest object for a given location Save activities and stats depending on value of isDryRun
async function ingestSingleLocation(
  locationName,
  athleteDoc,
  { isDryRun = false },
) {
  if (!configLocations[locationName]) {
    console.log(`Couldn't find location: ${JSON.stringify(locationName)}`);
    return false;
  }
  const {
    canonicalSegmentId,
  } = configLocations[locationName];
  try {
    const ingestor = new LocationIngest(athleteDoc, canonicalSegmentId);
    await ingestor.fetchActivities();
    console.log(`Found ${ingestor.getNumActivities()} activities`);
    if (!ingestor.getNumActivities()) {
      return false;
    }
    ingestor.prepareActivities();
    const invalidActivities = ingestor.getInvalidActivities();
    const numInvalid = invalidActivities.length;
    if (numInvalid) {
      console.log(JSON.stringify(invalidActivities, null, 2));
    }
    if (numInvalid / ingestor.getNumActivities() > MAX_INVALID_ACTIVITIES) {
      captureSentry('Exceeded max % invalid activities', 'ingestAthleteHistory', {
        level: 'warning',
        tags: { dryRun: isDryRun ? '1' : '0' },
        extra: {
          athlete: athleteDoc.id,
          numInvalid,
          activities: JSON.stringify(ingestor.getInvalidActivitiesIds()),
        },
      });
      return {};
    }
    if (!isDryRun) {
      await ingestor.saveActivities();
    }
    ingestor.generateStats();
    if (!isDryRun) {
      await ingestor.saveStats();
    }
    return {
      locationName,
      stats: ingestor.getStats(),
    };
  } catch (err) {
    captureSentry(err, 'ingestSingleLocation', {
      extra: {
        locationName,
        canonicalSegmentId,
        athletedId: athleteDoc.id,
      },
    });
  }
  return false;
}
async function ingestSingleLocation ( locationName , athleteDoc , { isDryRun = false } , ) { if ( ! configLocations [ locationName ] ) { console . log ( ` ${ JSON . stringify ( locationName ) } ` ) ; return false ; } const { canonicalSegmentId , } = configLocations [ locationName ] ; try { const ingestor = new LocationIngest ( athleteDoc , canonicalSegmentId ) ; await ingestor . fetchActivities ( ) ; console . log ( ` ${ ingestor . getNumActivities ( ) } ` ) ; if ( ! ingestor . getNumActivities ( ) ) { return false ; } ingestor . prepareActivities ( ) ; const invalidActivities = ingestor . getInvalidActivities ( ) ; const numInvalid = invalidActivities . length ; if ( numInvalid ) { console . log ( JSON . stringify ( invalidActivities , null , 2 ) ) ; } if ( numInvalid / ingestor . getNumActivities ( ) > MAX_INVALID_ACTIVITIES ) { captureSentry ( 'Exceeded max % invalid activities' , 'ingestAthleteHistory' , { level : 'warning' , tags : { dryRun : isDryRun ? '1' : '0' } , extra : { athlete : athleteDoc . id , numInvalid , activities : JSON . stringify ( ingestor . getInvalidActivitiesIds ( ) ) , } , } ) ; return { } ; } if ( ! isDryRun ) { await ingestor . saveActivities ( ) ; } ingestor . generateStats ( ) ; if ( ! isDryRun ) { await ingestor . saveStats ( ) ; } return { locationName , stats : ingestor . getStats ( ) , } ; } catch ( err ) { captureSentry ( err , 'ingestSingleLocation' , { extra : { locationName , canonicalSegmentId , athletedId : athleteDoc . id , } , } ) ; } return false ; }
Create LocationIngest object for a given location
 Save activities and stats depending on value of isDryRun
Create LocationIngest object for a given location Save activities and stats depending on value of isDryRun
// @todo Report error // Regenerates complete stats from all activities // but only keeps a copy of this location's stats // Merges this location's stats // back into complete stats then saves // Not sure why I did it this way 🤷‍♂️