Skip to content

Commit

Permalink
Refactoring and code improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewpetro committed Feb 15, 2024
1 parent dc328a2 commit b4623c7
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 20 deletions.
16 changes: 16 additions & 0 deletions src/sunrise-sunset/interfaces/sunrise-sunset-response.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export interface SunriseSunsetResponse {
results: {
sunrise: string
sunset: string
solar_noon?: string
day_length?: number
civil_twilight_begin?: string
civil_twilight_end?: string
nautical_twilight_begin?: string
nautical_twilight_end?: string
astronomical_twilight_begin?: string
astronomical_twilight_end?: string
}
status?: string
tzid?: string
}
8 changes: 8 additions & 0 deletions src/sunrise-sunset/interfaces/sunrise-sunset.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface SunriseSunset {
sunrise: string
sunset: string
}

export interface SunriseSunsets {
[date: string]: SunriseSunset
}
20 changes: 20 additions & 0 deletions src/sunrise-sunset/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { MangoQuery } from 'nano'

export const sunriseSunsetQueryBuilder = (startDate: string, endDate: string): MangoQuery => ({
selector: {
$and: [
{
_id: {
$gte: startDate,
},
},
{
_id: {
$lte: endDate,
},
},
],
},
sort: [{ _id: 'asc' }],
limit: 10000,
})
85 changes: 65 additions & 20 deletions src/sunrise-sunset/sunrise-sunset.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,33 @@ import EnvironmentVariables from '@/environment-variables'
import { Injectable, OnModuleInit } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import { DocumentScope } from 'nano'
import { SunriseSunsetDocument } from './interfaces/sunrise-sunset-document.interface'
import axios, { AxiosInstance } from 'axios'
import { SunriseSunsetDocument } from './interfaces/sunrise-sunset-document.interface'
import { SunriseSunsetResponse } from './interfaces/sunrise-sunset-response.interface'
import { sunriseSunsetQueryBuilder } from './queries'
import { addDays, format, parseISO } from 'date-fns'
import { SunriseSunsets } from './interfaces/sunrise-sunset.interface'

type SunriseSunsetResponse =
| {
results: {
sunrise: string
sunset: string
solar_noon: string
day_length: number
civil_twilight_begin: string
civil_twilight_end: string
nautical_twilight_begin: string
nautical_twilight_end: string
astronomical_twilight_begin: string
astronomical_twilight_end: string
}
status: string
tzid: string
const sunriseSunsetToDbDocument = ({ results }: SunriseSunsetResponse) => {
const { sunrise, sunset } = results
return {
// The ID is the date of the sunrise/sunset.
// Slicing off the first 10 characters gives us that without having to
// parse and reformat the date.
_id: sunrise.slice(0, 10),
sunrise,
sunset,
} as SunriseSunsetDocument
}

const dbDocumentsToSunriseSunsets = (documents: SunriseSunsetDocument[]) =>
documents.reduce((accumulator, document) => {
accumulator[document._id] = {
sunrise: document.sunrise,
sunset: document.sunset,
}
| undefined
return accumulator
}, {} as SunriseSunsets)

@Injectable()
export class SunriseSunsetService implements OnModuleInit {
Expand All @@ -42,15 +48,54 @@ export class SunriseSunsetService implements OnModuleInit {
lat: this.configService.get<number>('LATITUDE', { infer: true }),
lng: this.configService.get<number>('LONGITUDE', { infer: true }),
formatted: 0,
tzid: 'America/Phoenix',
},
})
this.db = this.databaseService.getDatabaseConnection(
this.configService.get<SunriseSunsetDocument>('SUNRISE_SUNSET_DB_NAME', { infer: true })
)
}

private async getSunriseSunsetFromApi(date: string): Promise<SunriseSunsetResponse> {
const response = await this.axiosInstance.get<SunriseSunsetResponse>('/', { params: { date } })
public async getSunriseSunsets(startDate: string, endDate: string) {
const dbDocs = await this.getSunriseSunsetsFromDb(startDate, endDate)
const sunriseSunsets = dbDocumentsToSunriseSunsets(dbDocs)

const start = parseISO(startDate)
const end = parseISO(endDate)

// Iterate through each day between the start and end dates
for (let date = start; date <= end; date = addDays(date, 1)) {
const dateString = format(date, 'yyyy-MM-dd')

// If we don't have a sunrise/sunset for the date, fetch it from the API,
// save it to the database and add to the sunriseSunsets object.
if (!sunriseSunsets[dateString]) {
const sunriseSunsetResponse = await this.getSunriseSunsetFromApi(dateString)
sunriseSunsets[dateString] = {
sunrise: sunriseSunsetResponse.results.sunrise,
sunset: sunriseSunsetResponse.results.sunset,
}
// We don't need to wait for the insert to complete, so we don't await it.
// If it fails, log it and move on.
this.insertSunriseSunset(sunriseSunsetToDbDocument(sunriseSunsetResponse)).catch((e) => {
console.error(e, `Failed to insert sunrise/sunset for ${dateString}`)
})
}
}
return sunriseSunsets
}

private async getSunriseSunsetFromApi(date: string) {
const response = await this.axiosInstance.get<SunriseSunsetResponse>('', { params: { date } })
return response.data
}

private async getSunriseSunsetsFromDb(startDate: string, endDate: string) {
const result = await this.db.find(sunriseSunsetQueryBuilder(startDate, endDate))
return result.docs
}

private async insertSunriseSunset(sunriseSunsetDocument: SunriseSunsetDocument) {
await this.db.insert(sunriseSunsetDocument)
}
}

0 comments on commit b4623c7

Please sign in to comment.