cityssm/node-green-button-parser

View on GitHub
helpers.ts

Summary

Maintainability
A
3 hrs
Test Coverage
// eslint-disable-next-line eslint-comments/disable-enable-pair
/* eslint-disable @typescript-eslint/indent */

import type {
  GreenButtonContentType,
  GreenButtonEntry,
  GreenButtonEntryWithApplicationInformationContent,
  GreenButtonEntryWithAuthorizationContent,
  GreenButtonEntryWithBatchListContent,
  GreenButtonEntryWithCustomerAccountContent,
  GreenButtonEntryWithCustomerAgreementContent,
  GreenButtonEntryWithCustomerContent,
  GreenButtonEntryWithElectricPowerQualitySummaryContent,
  GreenButtonEntryWithIntervalBlockContent,
  GreenButtonEntryWithLocalTimeParametersContent,
  GreenButtonEntryWithMeterContent,
  GreenButtonEntryWithMeterReadingContent,
  GreenButtonEntryWithReadingTypeContent,
  GreenButtonEntryWithServiceLocationContent,
  GreenButtonEntryWithServiceStatusContent,
  GreenButtonEntryWithServiceSupplierContent,
  GreenButtonEntryWithUsagePointContent,
  GreenButtonEntryWithUsageSummaryContent,
  GreenButtonJson,
  GreenButtonLinks
} from './types/entryTypes.js'

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'ApplicationInformation'
): GreenButtonEntryWithApplicationInformationContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'Authorization'
): GreenButtonEntryWithAuthorizationContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'BatchList'
): GreenButtonEntryWithBatchListContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'Customer'
): GreenButtonEntryWithCustomerContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'CustomerAccount'
): GreenButtonEntryWithCustomerAccountContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'CustomerAgreement'
): GreenButtonEntryWithCustomerAgreementContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'ElectricPowerQualitySummary'
): GreenButtonEntryWithElectricPowerQualitySummaryContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'IntervalBlock'
): GreenButtonEntryWithIntervalBlockContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'LocalTimeParameters'
): GreenButtonEntryWithLocalTimeParametersContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'Meter'
): GreenButtonEntryWithMeterContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'MeterReading'
): GreenButtonEntryWithMeterReadingContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'ReadingType'
): GreenButtonEntryWithReadingTypeContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'ServiceLocation'
): GreenButtonEntryWithServiceLocationContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'ServiceStatus'
): GreenButtonEntryWithServiceStatusContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'ServiceSupplier'
): GreenButtonEntryWithServiceSupplierContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'UsagePoint'
): GreenButtonEntryWithUsagePointContent[]

export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: 'UsageSummary'
): GreenButtonEntryWithUsageSummaryContent[]

/**
 * Filters entries in a Green Button object to only include entries of a given content type.
 * @param {GreenButtonJson} greenButtonJson Green Button object
 * @param {GreenButtonContentType} contentType Content type
 * @returns {GreenButtonEntry[]} A filtered list of Green Button entries
 */
export function getEntriesByContentType(
  greenButtonJson: GreenButtonJson,
  contentType: GreenButtonContentType
): GreenButtonEntry[] {
  const entries: GreenButtonEntry[] = []

  for (const entry of greenButtonJson.entries) {
    if (Object.hasOwn(entry.content, contentType)) {
      entries.push(entry)
    }
  }

  return entries
}

/**
 * Filters entries in a Green Button object to only include entries with a specific link value.
 * @param {GreenButtonJson} greenButtonJson Green Button object
 * @param {string} link The link to look for.
 * @param {keyof GreenButtonLinks} relationship The link relationship (i.e. self, up, related)
 * @returns {GreenButtonEntry[]} A filtered list of Green Button entries
 */
export function getEntriesByLink(
  greenButtonJson: GreenButtonJson,
  link: string,
  relationship: keyof GreenButtonLinks
): GreenButtonEntry[] {
  const entries: GreenButtonEntry[] = []

  for (const entry of greenButtonJson.entries) {
    if (
      Object.hasOwn(entry.links, relationship) &&
      ((typeof entry.links[relationship] === 'string' &&
        entry.links[relationship] === link) ||
        entry.links[relationship]?.includes(link))
    ) {
      entries.push(entry)
    }
  }

  return entries
}

/**
 * Finds the related MeterReading entry.
 * @param {GreenButtonJson} greenButtonJson Green Button object
 * @param {GreenButtonEntryWithIntervalBlockContent} entryWithIntervalBlock A Green Button entry that includes IntervalBlock content.
 * @returns {GreenButtonEntryWithMeterReadingContent | undefined} A related Green button entry that includes MeterReading content.
 */
export function getMeterReadingEntryFromIntervalBlockEntry(
  greenButtonJson: GreenButtonJson,
  entryWithIntervalBlock: GreenButtonEntryWithIntervalBlockContent
): GreenButtonEntryWithMeterReadingContent | undefined {
  const possibleMeterReadingEntries = getEntriesByLink(
    greenButtonJson,
    entryWithIntervalBlock.links.up ?? '',
    'related'
  )

  const meterReadingEntries = possibleMeterReadingEntries.filter(
    (possibleEntry) => {
      return possibleEntry.content.MeterReading !== undefined
    }
  )

  if (meterReadingEntries.length === 0) {
    return undefined
  }

  return meterReadingEntries[0] as GreenButtonEntryWithMeterReadingContent
}

/**
 * Finds the related ReadingType entry.
 * @param {GreenButtonJson} greenButtonJson Green Button object
 * @param {GreenButtonEntryWithMeterReadingContent} entryWithMeterReading A Green Button entry that includes MeterReading content.
 * @returns {GreenButtonEntryWithReadingTypeContent | undefined} A related Green Button entry with ReadingType content.
 */
export function getReadingTypeEntryFromMeterReadingEntry(
  greenButtonJson: GreenButtonJson,
  entryWithMeterReading: GreenButtonEntryWithMeterReadingContent
): GreenButtonEntryWithReadingTypeContent | undefined {
  for (const relatedLink of entryWithMeterReading.links.related ?? []) {
    const possibleReadingTypeEntries = getEntriesByLink(
      greenButtonJson,
      relatedLink,
      'self'
    )

    const readingTypeEntries = possibleReadingTypeEntries.filter(
      (possibleEntry) => {
        return possibleEntry.content.ReadingType !== undefined
      }
    )

    if (readingTypeEntries.length > 0) {
      return readingTypeEntries[0] as GreenButtonEntryWithReadingTypeContent
    }
  }

  return undefined
}

/**
 * Finds the related ReadingType entry.
 * @param {GreenButtonJson} greenButtonJson Green Button object
 * @param {GreenButtonEntryWithIntervalBlockContent} entryWithIntervalBlock A Green Button entry that includes IntervalBlock content.
 * @returns {GreenButtonEntryWithReadingTypeContent | undefined} A related Green Button entry with ReadingType content.
 */
export function getReadingTypeEntryFromIntervalBlockEntry(
  greenButtonJson: GreenButtonJson,
  entryWithIntervalBlock: GreenButtonEntryWithIntervalBlockContent
): GreenButtonEntryWithReadingTypeContent | undefined {
  const meterReadingEntry = getMeterReadingEntryFromIntervalBlockEntry(
    greenButtonJson,
    entryWithIntervalBlock
  )

  if (meterReadingEntry === undefined) {
    return undefined
  }

  return getReadingTypeEntryFromMeterReadingEntry(
    greenButtonJson,
    meterReadingEntry
  )
}

/**
 * Finds the related UsagePoint entry.
 * @param {GreenButtonJson} greenButtonJson Green Button object
 * @param {GreenButtonEntryWithMeterReadingContent | GreenButtonEntryWithUsageSummaryContent} entry A Green Button entry that includes either MeterReading or UsageSummary content.
 * @returns {GreenButtonEntryWithUsagePointContent | undefined} A related Green Button entry with UsagePoint content.
 */
export function getUsagePointEntryFromEntry(
  greenButtonJson: GreenButtonJson,
  entry:
    | GreenButtonEntryWithMeterReadingContent
    | GreenButtonEntryWithUsageSummaryContent
): GreenButtonEntryWithUsagePointContent | undefined {
  const possibleUsagePointEntries = getEntriesByLink(
    greenButtonJson,
    entry.links.up ?? '',
    'related'
  )

  const usagePointEntries = possibleUsagePointEntries.filter(
    (possibleEntry) => {
      return possibleEntry.content.UsagePoint !== undefined
    }
  )

  if (usagePointEntries.length > 0) {
    return usagePointEntries[0] as GreenButtonEntryWithUsagePointContent
  }
  return undefined
}

/**
 * Finds the related UsagePoint entry.
 * @param {GreenButtonJson} greenButtonJson Green Button object
 * @param {GreenButtonEntryWithIntervalBlockContent} entryWithIntervalBlock A Green Button entry that includes IntervalBlock content.
 * @returns {GreenButtonEntryWithUsagePointContent | undefined} A related Green Button entry with UsagePoint content.
 */
export function getUsagePointEntryFromIntervalBlockEntry(
  greenButtonJson: GreenButtonJson,
  entryWithIntervalBlock: GreenButtonEntryWithIntervalBlockContent
): GreenButtonEntryWithUsagePointContent | undefined {
  const meterReadingEntry = getMeterReadingEntryFromIntervalBlockEntry(
    greenButtonJson,
    entryWithIntervalBlock
  )

  if (meterReadingEntry === undefined) {
    return undefined
  }

  return getUsagePointEntryFromEntry(greenButtonJson, meterReadingEntry)
}

export default {
  getEntriesByContentType,
  getEntriesByLink,
  getMeterReadingEntryFromIntervalBlockEntry,
  getReadingTypeEntryFromMeterReadingEntry,
  getReadingTypeEntryFromIntervalBlockEntry,
  getUsagePointEntryFromEntry,
  getUsagePointEntryFromIntervalBlockEntry
}