194 lines
5.1 KiB
TypeScript
194 lines
5.1 KiB
TypeScript
|
import {
|
||
|
DatasourceFieldTypes,
|
||
|
Integration,
|
||
|
QueryTypes,
|
||
|
} from "../definitions/datasource"
|
||
|
import { IntegrationBase } from "./base/IntegrationBase"
|
||
|
import { GoogleSpreadsheet } from "google-spreadsheet"
|
||
|
|
||
|
module GoogleSheetsModule {
|
||
|
interface GoogleSheetsConfig {
|
||
|
spreadsheetId: string
|
||
|
clientEmail: string
|
||
|
privateKey: string
|
||
|
}
|
||
|
|
||
|
const SCHEMA: Integration = {
|
||
|
docs: "https://developers.google.com/sheets/api/quickstart/nodejs",
|
||
|
description:
|
||
|
"Create and collaborate on online spreadsheets in real-time and from any device. ",
|
||
|
friendlyName: "Google Sheets",
|
||
|
datasource: {
|
||
|
spreadsheetId: {
|
||
|
type: DatasourceFieldTypes.STRING,
|
||
|
required: true,
|
||
|
},
|
||
|
clientEmail: {
|
||
|
type: DatasourceFieldTypes.STRING,
|
||
|
required: true,
|
||
|
},
|
||
|
privateKey: {
|
||
|
type: DatasourceFieldTypes.LONGFORM,
|
||
|
required: true,
|
||
|
},
|
||
|
},
|
||
|
query: {
|
||
|
create: {
|
||
|
type: QueryTypes.FIELDS,
|
||
|
fields: {
|
||
|
sheet: {
|
||
|
type: "string",
|
||
|
required: true,
|
||
|
},
|
||
|
row: {
|
||
|
type: QueryTypes.JSON,
|
||
|
required: true,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
read: {
|
||
|
type: QueryTypes.FIELDS,
|
||
|
fields: {
|
||
|
sheet: {
|
||
|
type: "string",
|
||
|
required: true,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
update: {
|
||
|
type: QueryTypes.FIELDS,
|
||
|
fields: {
|
||
|
sheet: {
|
||
|
type: "string",
|
||
|
required: true,
|
||
|
},
|
||
|
rowIndex: {
|
||
|
type: "number",
|
||
|
required: true,
|
||
|
},
|
||
|
row: {
|
||
|
type: QueryTypes.JSON,
|
||
|
required: true,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
delete: {
|
||
|
type: QueryTypes.FIELDS,
|
||
|
fields: {
|
||
|
sheet: {
|
||
|
type: "string",
|
||
|
required: true,
|
||
|
},
|
||
|
rowIndex: {
|
||
|
type: "number",
|
||
|
required: true,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
class GoogleSheetsIntegration implements IntegrationBase {
|
||
|
private readonly config: GoogleSheetsConfig
|
||
|
private client: any
|
||
|
|
||
|
constructor(config: GoogleSheetsConfig) {
|
||
|
this.config = config
|
||
|
this.client = new GoogleSpreadsheet(this.config.spreadsheetId)
|
||
|
}
|
||
|
|
||
|
async connect() {
|
||
|
try {
|
||
|
await this.client.useServiceAccountAuth({
|
||
|
// env var values are copied from service account credentials generated by google
|
||
|
// see "Authentication" section in docs for more info
|
||
|
client_email: this.config.clientEmail,
|
||
|
private_key: this.config.privateKey,
|
||
|
})
|
||
|
await this.client.loadInfo()
|
||
|
} catch (err) {
|
||
|
console.error("Error connecting to google sheets", err)
|
||
|
throw err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
buildRowObject(headers: string[], values: string[]) {
|
||
|
const rowObject = {}
|
||
|
for (let i = 0; i < headers.length; i++) {
|
||
|
rowObject[headers[i]] = values[i]
|
||
|
}
|
||
|
return rowObject
|
||
|
}
|
||
|
|
||
|
async create(query: { sheet: string; row: string }) {
|
||
|
try {
|
||
|
await this.connect()
|
||
|
const sheet = await this.client.sheetsByTitle[query.sheet]
|
||
|
const rowToInsert = JSON.parse(query.row)
|
||
|
const row = await sheet.addRow(rowToInsert)
|
||
|
return [this.buildRowObject(sheet.headerValues, row._rawData)]
|
||
|
} catch (err) {
|
||
|
console.error("Error writing to google sheets", err)
|
||
|
throw err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async read(query: { sheet: string }) {
|
||
|
try {
|
||
|
await this.connect()
|
||
|
const sheet = await this.client.sheetsByTitle[query.sheet]
|
||
|
const rows = await sheet.getRows()
|
||
|
const headerValues = sheet.headerValues
|
||
|
const response = []
|
||
|
for (let row of rows) {
|
||
|
response.push(this.buildRowObject(headerValues, row._rawData))
|
||
|
}
|
||
|
return response
|
||
|
} catch (err) {
|
||
|
console.error("Error reading from google sheets", err)
|
||
|
throw err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async update(query: { sheet: string; rowIndex: number; row: string }) {
|
||
|
try {
|
||
|
await this.connect()
|
||
|
const sheet = await this.client.sheetsByTitle[query.sheet]
|
||
|
const rows = await sheet.getRows()
|
||
|
const row = rows[query.rowIndex]
|
||
|
if (row) {
|
||
|
const updateValues = JSON.parse(query.row)
|
||
|
for (let key in updateValues) {
|
||
|
row[key] = updateValues[key]
|
||
|
}
|
||
|
await row.save()
|
||
|
return [this.buildRowObject(sheet.headerValues, row._rawData)]
|
||
|
} else {
|
||
|
throw new Error("Row does not exist.")
|
||
|
}
|
||
|
} catch (err) {
|
||
|
console.error("Error reading from google sheets", err)
|
||
|
throw err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async delete(query: { sheet: string; rowIndex: number }) {
|
||
|
await this.connect()
|
||
|
const sheet = await this.client.sheetsByTitle[query.sheet]
|
||
|
const rows = await sheet.getRows()
|
||
|
const row = rows[query.rowIndex]
|
||
|
if (row) {
|
||
|
await row.delete()
|
||
|
return [{ deleted: query.rowIndex }]
|
||
|
} else {
|
||
|
throw new Error("Row does not exist.")
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = {
|
||
|
schema: SCHEMA,
|
||
|
integration: GoogleSheetsIntegration,
|
||
|
}
|
||
|
}
|