Skip to content

Commit

Permalink
converted project to typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
sophyphreak committed Jan 16, 2022
1 parent aa47e57 commit 305b85d
Show file tree
Hide file tree
Showing 24 changed files with 699 additions and 226 deletions.
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
engine-strict=true
3 changes: 1 addition & 2 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"semi": false,
"singleQuote": true,
"arrowParens": "avoid"
"singleQuote": true
}
19 changes: 13 additions & 6 deletions app.js → app.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import createError from 'http-errors'
import express from 'express'
import express, { Request, Response, Application } from 'express'
import cookieParser from 'cookie-parser'
import logger from 'morgan'
import helmet from 'helmet'
import cors from 'cors'

import indexRouter from './routes/index.js'
import indexRouter from './routes/index'

import startCron from './cron/index.js'
// @ts-ignore
import startCron from './cron/index'
startCron()

import startup from './startup/index.js'
// @ts-ignore
import startup from './startup/index'
startup()

const app = express()
const app: Application = express()

app.use(helmet())
app.use(cors())
Expand All @@ -31,8 +33,13 @@ app.use(function (req, res, next) {
next(createError(404))
})

interface Error {
message: string
status: number
}

// error handler
app.use(function (err, req, res, next) {
app.use(function (err: Error, req: Request, res: Response) {
// set locals, only providing error in development
res.locals.message = err.message
res.locals.error = req.app.get('env') === 'development' ? err : {}
Expand Down
6 changes: 3 additions & 3 deletions cron/index.js → cron/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { CronJob as CronJob } from 'cron'
import updateRenewalLocations from '../updateRenewalLocations/index.js'
import updateRenewalLocations from '../updateRenewalLocations'

const startCron = () => {
const startCron = (): void => {
new CronJob(
'00 00 00 * * *',
() => updateRenewalLocations(),
(): Promise<void> => updateRenewalLocations(),
null,
true,
'America/Los_Angeles'
Expand Down
8 changes: 8 additions & 0 deletions fetchLatLong/fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const importDynamic = new Function('modulePath', 'return import(modulePath)')

const fetch = async (...args: any[]) => {
const module = await importDynamic('node-fetch')
return module.default(...args)
}

export default fetch
82 changes: 57 additions & 25 deletions fetchLatLong/index.js → fetchLatLong/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import fetch from 'node-fetch'
import { Location } from '../types'

const fetchLatLong = async locations => {
import fetch from './fetch'

const fetchLatLong = async (locations: Location[]): Promise<Location[]> => {
const locationsWithLatLong = locations.map(async (location, index) => {
await staggerRequest(index)
const uri = generateUri(location)
Expand All @@ -15,11 +17,14 @@ const fetchLatLong = async locations => {
}

// Google allows max 50 requests per second
const staggerRequest = async index => await timeout(100 * index)
const staggerRequest = async (index: number): Promise<void> => {
await timeout(100 * index)
}

const timeout = ms => new Promise(resolve => setTimeout(resolve, ms))
const timeout = (ms: number): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, ms))

const generateUri = location => {
const generateUri = (location: Location): string => {
const { address, city, zip } = location
const queryString = encodeURIComponent(`${address}, ${city} ${zip}`)
const uri = `https://maps.googleapis.com/maps/api/geocode/json?address=${queryString}&key=${process.env.GOOGLE_API_KEY}`
Expand All @@ -29,58 +34,85 @@ const generateUri = location => {
const printCoordinatesFoundMessage = ({
index,
location: { store, address, city, zip, latitude, longitude },
}) =>
}: {
index: number
location: Location
}): void =>
console.log(
`coordinates found for index ${index}: ${store} ${address}, ${city} ${zip} lat: ${latitude} lng: ${longitude}`
)

const MAX_RETRYS = 5
const MAX_RETRYS: number = 5

const attemptFetchAndLoopIfFails = async ({ location, index, uri }) => {
let data, ok, latitude, longitude
const attemptFetchAndLoopIfFails = async ({
location,
index,
uri,
}: {
location: Location
index: number
uri: string
}): Promise<Location> => {
let geoCodeData, ok, latitude, longitude
try {
for (let retryCount = 0; retryCount < MAX_RETRYS; retryCount++) {
;({ data, ok } = await attemptFetch(uri))
;({ geoCodeData, ok } = await attemptFetch(uri))
if (ok) {
break
}
printRequestFailedMessages({ location, index, data })
printRequestFailedMessages({ location, index, geoCodeData })
await timeout(1000)
}
if (ok) {
;({ latitude, longitude } = destructureLatLong(data))
if (ok && geoCodeData) {
;({ latitude, longitude } = destructureLatLong(geoCodeData))
}
location.latitude = latitude
location.longitude = longitude
location.latitude = latitude ?? null
location.longitude = longitude ?? null
} catch (error) {
console.error(error)
}
return location
}

const attemptFetch = async uri => {
interface GeoCodeData {
results: [{ geometry: { location: { lat: number; lng: number } } }]
status: string
}

const attemptFetch = async (
uri: string
): Promise<{ geoCodeData: GeoCodeData; ok: boolean }> => {
const response = await fetch(uri)
const data = await response.json()
const { status } = data
const geoCodeData = await response.json()
const { status } = geoCodeData
if (status !== 'OK') {
return { ok: false, data }
return { ok: false, geoCodeData }
}
return { data, ok: true }
return { geoCodeData, ok: true }
}

const printRequestFailedMessages = ({
location: { store, address, city, zip },
index,
data,
}) => {
geoCodeData,
}: {
location: Location
index: number
geoCodeData: GeoCodeData
}): void => {
console.log(
`No lat long returned for index ${index}: ${store} ${address}, ${city} ${zip}`
)
console.log('data:', data)
console.log('geoCodeData:', geoCodeData)
console.log('retrying...')
}

const destructureLatLong = data => {
interface Coordinates {
latitude: number
longitude: number
}

const destructureLatLong = (geoCodeData: GeoCodeData): Coordinates => {
const {
results: [
{
Expand All @@ -89,7 +121,7 @@ const destructureLatLong = data => {
},
},
],
} = data
} = geoCodeData
return { latitude, longitude }
}

Expand Down
21 changes: 18 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node app.js"
"start": "ts-node ./app.ts",
"dev": "ts-node-dev --respawn ./app.ts"
},
"type": "module",
"dependencies": {
"@prisma/client": "^3.7.0",
"cookie-parser": "~1.4.4",
Expand All @@ -20,7 +20,22 @@
"puppeteer": "^13.0.1"
},
"devDependencies": {
"@tsconfig/node16": "^1.0.2",
"@types/cookie-parser": "^1.4.2",
"@types/cors": "^2.8.12",
"@types/cron": "^1.7.3",
"@types/express": "^4.17.13",
"@types/http-errors": "^1.8.2",
"@types/morgan": "^1.9.3",
"@types/node": "^17.0.8",
"eslint-plugin-security": "^1.4.0",
"prisma": "^3.7.0"
"prisma": "^3.7.0",
"ts-node": "^10.4.0",
"ts-node-dev": "^1.1.8",
"typescript": "^4.5.4"
},
"engines": {
"node": ">=16.13.1",
"npm": ">=8.1.2"
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import prisma from './client.js'
import { Location } from '../types'

const activateActiveLocations = async renewalLocations => {
renewalLocations.forEach(async location => {
import prisma from './client'

const activateActiveLocations = async (
renewalLocations: Location[]
): Promise<void> => {
renewalLocations.forEach(async (location) => {
const { store, address, city, zip, telephone } = location
const locationRecord = await prisma.location.findFirst({
where: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import prisma from './client.js'
import { Location } from '../types'

const addNewLocationsToDatabase = async renewalLocations => {
await renewalLocations.forEach(async location => {
import prisma from './client'

const addNewLocationsToDatabase = async (
renewalLocations: Location[]
): Promise<void> => {
await renewalLocations.forEach(async (location: Location): Promise<void> => {
const { store, address, city, zip, telephone } = location
const locationExistsInDatabase = await prisma.location.findFirst({
where: {
Expand Down
6 changes: 0 additions & 6 deletions prisma/client.js

This file was deleted.

5 changes: 5 additions & 0 deletions prisma/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

export default prisma
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import prisma from './client.js'
import { Location } from '../types'

const deactiveInactiveLocations = async renewalLocations => {
import prisma from './client'

const deactiveInactiveLocations = async (renewalLocations: Location[]) => {
const activeLocationsInDatabase = await prisma.location.findMany({
where: { active: true },
})
for (let databaseLocation of activeLocationsInDatabase) {
const { id, store, address, city, zip, telephone } = databaseLocation
const isRenewalLocation = !!renewalLocations.find(location => {
const isRenewalLocation = !!renewalLocations.find((location) => {
if (
location.store === store &&
location.address === address &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import prisma from './client.js'
import prisma from './client'

const findLocationsWithoutLatLong = async () => {
const locationsWithoutLatLong = await prisma.location.findMany({
Expand Down
5 changes: 3 additions & 2 deletions prisma/retrieveLocations.js → prisma/retrieveLocations.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import prisma from './client.js'
import prisma from './client'
import { Location } from '../types/index'

const retrieveLocations = async () => {
const locations = await prisma.location.findMany({
const locations: Location[] = await prisma.location.findMany({
where: {
active: true,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import prisma from './client.js'
import { Location } from '../types'

const updateLocationsWithLatLong = async locations => {
import prisma from './client'

const updateLocationsWithLatLong = async (
locations: Location[]
): Promise<void> => {
for (let location of locations) {
const { id, latitude, longitude } = location
try {
Expand Down
26 changes: 0 additions & 26 deletions routes/index.js

This file was deleted.

Loading

0 comments on commit 305b85d

Please sign in to comment.