diff --git a/src/App.scss b/src/App.scss
index ade1014c..b9420145 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -3,3 +3,7 @@
margin-right: 0.25rem;
}
}
+
+.MuiSvgIcon-root {
+ margin-top: -4px;
+}
\ No newline at end of file
diff --git a/src/Cat/Cat.tsx b/src/Cat/Cat.tsx
index 78c91df1..08ad1318 100644
--- a/src/Cat/Cat.tsx
+++ b/src/Cat/Cat.tsx
@@ -313,6 +313,7 @@ const ShowCat = ({
)}
+
Battery
diff --git a/src/HistoricalData/HistoricalDataChart.tsx b/src/HistoricalData/HistoricalDataChart.tsx
index 67851b69..56c77d0e 100644
--- a/src/HistoricalData/HistoricalDataChart.tsx
+++ b/src/HistoricalData/HistoricalDataChart.tsx
@@ -1,9 +1,12 @@
import * as am4core from '@amcharts/amcharts4/core'
import * as am4charts from '@amcharts/amcharts4/charts'
-import React, { useEffect, useRef } from 'react'
+import React, { useEffect, useRef, useState } from 'react'
import { v4 } from 'uuid'
import Athena from 'aws-sdk/clients/athena'
import { exponential } from 'backoff'
+import { parseAthenaResult } from '../parseAthenaResult'
+import { Loading } from '../Loading/Loading'
+import { Error as ShowError } from '../Error/Error'
import './HistoricalDataChart.scss'
@@ -20,11 +23,32 @@ export const HistoricalDataChart = ({
}) => {
const chartRef = useRef()
const uuid = useRef(v4())
+ const [loading, setLoading] = useState(true)
+ const [error, setError] = useState()
useEffect(() => {
+ const chart = am4core.create(uuid.current, am4charts.XYChart)
+ chartRef.current = chart
+
+ const dateAxis = chart.xAxes.push(
+ new am4charts.DateAxis(),
+ )
+ dateAxis.fontSize = 10
+ dateAxis.renderer.minGridDistance = 60
+
+ const valueAxes = chart.yAxes.push(
+ new am4charts.ValueAxis(),
+ )
+ valueAxes.fontSize = 10
+
+ const series = chart.series.push(new am4charts.LineSeries())
+ series.dataFields.valueY = 'value'
+ series.dataFields.dateX = 'date'
+ series.tooltipText = '{value}'
+
athena
.startQueryExecution({
WorkGroup: athenaWorkGroup,
- QueryString: `SELECT * FROM ${athenaDataBase}.${athenaRawDataTable} WHERE deviceId='${deviceId}' AND reported.bat IS NOT NULL`,
+ QueryString: `SELECT reported.bat.ts as date, reported.bat.v as value FROM ${athenaDataBase}.${athenaRawDataTable} WHERE deviceId='${deviceId}' AND reported.bat IS NOT NULL ORDER BY reported.bat.v DESC LIMIT 100`,
})
.promise()
.then(({ QueryExecutionId }) => {
@@ -76,46 +100,30 @@ export const HistoricalDataChart = ({
reject(new Error(`Timed out waiting for query ${QueryExecutionId}`))
})
b.backoff()
- })
- .then(() => athena.getQueryResults({ QueryExecutionId }).promise())
+ }).then(() => athena.getQueryResults({ QueryExecutionId }).promise())
})
- .then(console.log)
- .catch(console.error)
-
- const chart = am4core.create(uuid.current, am4charts.XYChart)
- chartRef.current = chart
-
- const data = []
- let value = 50
- for (let i = 0; i < 300; i++) {
- const date = new Date()
- date.setHours(0, 0, 0, 0)
- date.setDate(i)
- value -= Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10)
- data.push({ date: date, value: value })
- }
-
- chart.data = data
-
- const dateAxis = chart.xAxes.push(
- new am4charts.DateAxis(),
- )
- dateAxis.fontSize = 10
- dateAxis.renderer.minGridDistance = 60
-
- const valueAxes = chart.yAxes.push(
- new am4charts.ValueAxis(),
- )
- valueAxes.fontSize = 10
+ .then(({ ResultSet }) => {
+ if (!ResultSet || !ResultSet.Rows) {
+ throw new Error(`No resultset returned.`)
+ }
+ return parseAthenaResult(ResultSet)
+ })
+ .then(data => {
+ setLoading(false)
+ chart.data = data
+ })
+ .catch(setError)
- const series = chart.series.push(new am4charts.LineSeries())
- series.dataFields.valueY = 'value'
- series.dataFields.dateX = 'date'
- series.tooltipText = '{value}'
return () => {
chartRef.current && chartRef.current.dispose()
}
- }, [athena, deviceId])
+ }, [athena, deviceId, setLoading, setError])
- return
+ return (
+ <>
+ {loading && }
+ {error && }
+
+ >
+ )
}
diff --git a/src/parseAthenaResult.spec.ts b/src/parseAthenaResult.spec.ts
new file mode 100644
index 00000000..4509a974
--- /dev/null
+++ b/src/parseAthenaResult.spec.ts
@@ -0,0 +1,62 @@
+import { parseAthenaResult } from './parseAthenaResult'
+
+describe('parseAthenaResult', () => {
+ it('parse an Athena result into an array of values', () => {
+ expect(
+ parseAthenaResult({
+ Rows: [
+ { Data: [{ VarCharValue: 'date' }, { VarCharValue: 'value' }] },
+ {
+ Data: [
+ { VarCharValue: '2019-08-01T10:29:54.406Z' },
+ { VarCharValue: '2607' },
+ ],
+ },
+ {
+ Data: [
+ { VarCharValue: '2019-07-31T08:34:20.765Z' },
+ { VarCharValue: '2046' },
+ ],
+ },
+ ],
+ ResultSetMetadata: {
+ ColumnInfo: [
+ {
+ CatalogName: 'hive',
+ SchemaName: '',
+ TableName: '',
+ Name: 'date',
+ Label: 'date',
+ Type: 'varchar',
+ Precision: 2147483647,
+ Scale: 0,
+ Nullable: 'UNKNOWN',
+ CaseSensitive: true,
+ },
+ {
+ CatalogName: 'hive',
+ SchemaName: '',
+ TableName: '',
+ Name: 'value',
+ Label: 'value',
+ Type: 'integer',
+ Precision: 10,
+ Scale: 0,
+ Nullable: 'UNKNOWN',
+ CaseSensitive: false,
+ },
+ ],
+ },
+ }),
+ ).toEqual([
+ {
+ date: '2019-08-01T10:29:54.406Z',
+ value: 2607,
+ },
+ {
+ date: '2019-07-31T08:34:20.765Z',
+ value: 2046,
+ },
+ ])
+ })
+})
diff --git a/src/parseAthenaResult.ts b/src/parseAthenaResult.ts
new file mode 100644
index 00000000..5eb1e242
--- /dev/null
+++ b/src/parseAthenaResult.ts
@@ -0,0 +1,40 @@
+import Athena from 'aws-sdk/clients/athena'
+
+const parseValue = ({ value, type }: { value?: string; type: string }) => {
+ if (value === undefined) {
+ return value
+ }
+ switch (type) {
+ case 'integer':
+ return parseInt(value, 10)
+ default:
+ return value
+ }
+}
+
+export type ParsedResult = { [key: string]: string | number }[]
+
+export const parseAthenaResult = ({
+ Rows,
+ ResultSetMetadata,
+}: Athena.ResultSet): ParsedResult => {
+ if (!Rows || !ResultSetMetadata || !ResultSetMetadata.ColumnInfo) {
+ return []
+ }
+ const { ColumnInfo } = ResultSetMetadata
+ return Rows.slice(1).map(({ Data }) => {
+ if (!Data) {
+ return {}
+ }
+ return ColumnInfo.reduce(
+ (result, { Name, Type }, key) => ({
+ ...result,
+ [Name]: parseValue({
+ value: Data[key].VarCharValue,
+ type: Type,
+ }),
+ }),
+ {},
+ )
+ })
+}