analytics-reporter
Version:
A lightweight command line tool for reporting and publishing analytics data from a Google Analytics account.
105 lines (90 loc) • 2.89 kB
JavaScript
const ANALYTICS_DATA_TABLE_NAME = "analytics_data"
const knex = require("knex")
const moment = require("moment-timezone")
const Promise = require("bluebird")
const config = require("../config")
const publish = (results) => {
const db = knex({ client: "pg", connection: config.postgres })
if (results.query.dimensions.match(/ga:date/)) {
return _writeRegularResults({ db, results }).then(() => db.destroy())
} else {
return Promise.resolve()
}
}
const _dataForDataPoint = (dataPoint, { realtime } = {}) => {
const data = Object.assign({}, dataPoint)
let dateTime
if (realtime) {
dateTime = (new Date()).toISOString()
} else {
dateTime = _dateTimeForDataPoint(dataPoint)
}
delete data.date
delete data.hour
return {
date_time: dateTime,
data: data,
}
}
const _dateTimeForDataPoint = (dataPoint) => {
let dateString = dataPoint.date
if (dataPoint.hour) {
dateString = `${dateString}T${dataPoint.hour}:00:00`
} else {
dateString = `${dateString}T00:00:00`
}
if (!isNaN(Date.parse(dateString))) {
return moment.tz(dateString, config.timezone).toISOString()
}
}
const _queryForExistingRow = ({ db, row }) => {
query = db(ANALYTICS_DATA_TABLE_NAME)
Object.keys(row).forEach(key => {
if (row[key] === undefined) {
return
} else if (key === "data") {
const dataQuery = Object.assign({}, row.data)
delete dataQuery.visits
delete dataQuery.users
Object.keys(dataQuery).forEach(dataKey => {
query = query.whereRaw(`data->>'${dataKey}' = ?`, [dataQuery[dataKey]])
})
} else {
query = query.where({ [key]: row[key] })
}
})
return query.select()
}
const _handleExistingRow = ({ db, existingRow, newRow }) => {
if (existingRow.data.visits != newRow.data.visits || existingRow.data.users != newRow.data.users) {
return db(ANALYTICS_DATA_TABLE_NAME).where({ id: existingRow.id }).update(newRow)
}
}
const _rowForDataPoint = ({ results, dataPoint, realtime }) => {
const row = _dataForDataPoint(dataPoint, { realtime })
row.report_name = results.name
row.report_agency = results.agency
return row
}
const _writeRegularResults = ({ db, results }) => {
const rows = results.data.map(dataPoint => {
return _rowForDataPoint({ results, dataPoint })
})
const rowsToInsert = []
return Promise.each(rows, row => {
return _queryForExistingRow({ db, row }).then(results => {
if (row.date_time === undefined) {
return
} else if (results.length === 0) {
rowsToInsert.push(row)
} else if (results.length === 1) {
return _handleExistingRow({ db, existingRow: results[0], newRow: row })
}
})
}).then(() => {
return db(ANALYTICS_DATA_TABLE_NAME).insert(rowsToInsert)
}).then(() => {
return db.destroy()
})
}
module.exports = { publish, ANALYTICS_DATA_TABLE_NAME }