From 6e66d31942e731e0f02a47a507662c9b3d777327 Mon Sep 17 00:00:00 2001 From: mtgto Date: Sun, 1 Dec 2019 11:42:05 +0900 Subject: [PATCH] Add types to datasources --- src/lib/DataSourceDefinition/Athena.ts | 27 +++++++++-------- src/lib/DataSourceDefinition/Base.ts | 29 ++++++++++++++---- src/lib/DataSourceDefinition/BigQuery.ts | 31 ++++++++++++-------- src/lib/DataSourceDefinition/Mysql.ts | 22 ++++++++------ src/lib/DataSourceDefinition/Postgres.ts | 26 +++++++++------- src/lib/DataSourceDefinition/SQLite3.ts | 26 +++++++++------- src/lib/DataSourceDefinition/TreasureData.ts | 22 +++++++------- src/lib/Util/stripHeredoc.ts | 2 +- 8 files changed, 113 insertions(+), 72 deletions(-) diff --git a/src/lib/DataSourceDefinition/Athena.ts b/src/lib/DataSourceDefinition/Athena.ts index 48487ba3..ed6b6601 100644 --- a/src/lib/DataSourceDefinition/Athena.ts +++ b/src/lib/DataSourceDefinition/Athena.ts @@ -1,17 +1,17 @@ import AthenaClient from "../AthenaClient"; -import Base from "./Base"; +import Base, { ConfigSchemaType } from "./Base"; import Util from "../Util"; export default class Athena extends Base { client: AthenaClient; - static get key() { + static get key(): string { return "athena"; } - static get label() { + static get label(): string { return "Amazon Athena"; } - static get configSchema() { + static get configSchema(): ConfigSchemaType { return [ { name: "region", @@ -57,21 +57,24 @@ export default class Athena extends Base { return { fields, rows }; } - cancel() { - return this.client.cancel(); + cancel(): void { + this.client.cancel(); } - async connectionTest() { + async connectionTest(): Promise { await this.client.execute("select 1"); - return; } - async fetchTables() { + async fetchTables(): Promise<{ name: string; type: string; schema?: string }[]> { const rows = await this.client.execute("show tables"); - return rows.map(row => ({ name: row[0], type: "table" })); + return rows.map(row => ({ name: row[0]!, type: "table" })); } - async fetchTableSummary({ name }) { + async fetchTableSummary({ + name + }: { + name: string; + }): Promise<{ name: string; defs: { fields: string[]; rows: (string | null)[][] }; schema?: string }> { const rows = await this.client.execute(`describe ${name}`); const defs = { fields: ["name", "type"], @@ -84,7 +87,7 @@ export default class Athena extends Base { return { name, defs }; } - descriptionTable() { + descriptionTable(): string { return Util.stripHeredoc(` |region|${this.config.region}| |database|${this.config.database}| diff --git a/src/lib/DataSourceDefinition/Base.ts b/src/lib/DataSourceDefinition/Base.ts index c41b2506..216418e0 100644 --- a/src/lib/DataSourceDefinition/Base.ts +++ b/src/lib/DataSourceDefinition/Base.ts @@ -7,20 +7,37 @@ export default abstract class Base { static get label(): string { throw new Error("Not Implemented"); } + static get configSchema(): ConfigSchemaType { + throw new Error("Not Implemented"); + } constructor(config) { this.config = config; } - abstract execute(query); + abstract execute(query: string): Promise; - abstract cancel(); + // @todo Set return type as Promise ? + abstract cancel(): void | Promise; - abstract connectionTest(); + // @todo Define type of the result (boolean or void ?) + abstract connectionTest(): Promise; - abstract fetchTables(); + abstract fetchTables(): Promise<{ name: string; type: string; schema?: string }[]>; - abstract descriptionTable(); + abstract descriptionTable(): string; - abstract fetchTableSummary(args); + abstract fetchTableSummary( + args: any + ): Promise<{ name: string; defs: { fields: string[]; rows: (string | null)[][] }; schema?: string }>; } + +export type ConfigSchemaType = { + readonly name: string; + readonly label: string; + readonly type: string; + readonly placeholder?: string | number; + readonly required?: boolean; + readonly values?: string[]; + readonly default?: string; +}[]; diff --git a/src/lib/DataSourceDefinition/BigQuery.ts b/src/lib/DataSourceDefinition/BigQuery.ts index 670b4880..c06d15f6 100644 --- a/src/lib/DataSourceDefinition/BigQuery.ts +++ b/src/lib/DataSourceDefinition/BigQuery.ts @@ -1,17 +1,17 @@ import bigquery from "@google-cloud/bigquery"; -import Base from "./Base"; +import Base, { ConfigSchemaType } from "./Base"; import { flatten } from "lodash"; export default class BigQuery extends Base { _cancel: any; - static get key() { + static get key(): string { return "bigquery"; } - static get label() { + static get label(): string { return "BigQuery"; } - static get configSchema() { + static get configSchema(): ConfigSchemaType { return [ { name: "project", @@ -28,7 +28,7 @@ export default class BigQuery extends Base { ]; } - execute(query) { + execute(query: string) { this._cancel = null; return new Promise((resolve, reject) => { bigquery(this.config).startQuery(query, (err, job) => { @@ -52,18 +52,17 @@ export default class BigQuery extends Base { }); } - cancel() { + cancel(): void { return this._cancel && this._cancel(); } - async connectionTest() { + async connectionTest(): Promise { await bigquery(this.config).query("select 1"); - return true; } - async fetchTables() { - const [datasets] = await bigquery(this.config).getDatasets(); - const promises = datasets.map(async dataset => { + async fetchTables(): Promise<{ name: string; type: string; schema?: string }[]> { + const [datasets]: [any[]] = await bigquery(this.config).getDatasets(); + const promises = datasets.map>(async dataset => { const [tables] = await dataset.getTables(); return tables.map(table => ({ schema: dataset.id, @@ -75,7 +74,13 @@ export default class BigQuery extends Base { return flatten(results); } - async fetchTableSummary({ schema, name }) { + async fetchTableSummary({ + schema, + name + }: { + schema: string; + name: string; + }): Promise<{ name: string; defs: { fields: string[]; rows: (string | null)[][] }; schema?: string }> { const [metadata] = await bigquery(this.config) .dataset(schema) .table(name) @@ -88,7 +93,7 @@ export default class BigQuery extends Base { return { schema, name, defs }; } - descriptionTable() { + descriptionTable(): string { return `|project|${this.config.project}|`; } } diff --git a/src/lib/DataSourceDefinition/Mysql.ts b/src/lib/DataSourceDefinition/Mysql.ts index d68a4485..9acf5ba9 100644 --- a/src/lib/DataSourceDefinition/Mysql.ts +++ b/src/lib/DataSourceDefinition/Mysql.ts @@ -1,18 +1,18 @@ import mysql from "mysql2"; -import Base from "./Base"; +import Base, { ConfigSchemaType } from "./Base"; import Util from "../Util"; import { zipObject } from "lodash"; export default class Mysql extends Base { currentConnection: any; - static get key() { + static get key(): string { return "mysql"; } - static get label() { + static get label(): string { return "MySQL"; } - static get configSchema() { + static get configSchema(): ConfigSchemaType { return [ { name: "host", label: "Host", type: "string", placeholder: "localhost" }, { name: "port", label: "Port", type: "number", placeholder: 3306 }, @@ -31,7 +31,7 @@ export default class Mysql extends Base { return this._execute(query); } - cancel() { + cancel(): Promise { const tid = this.currentConnection && this.currentConnection.threadId; if (!tid) return Promise.resolve(); @@ -43,7 +43,7 @@ export default class Mysql extends Base { return true; } - async fetchTables() { + async fetchTables(): Promise<{ name: string; type: string; schema?: string }[]> { const query = Util.stripHeredoc(` select table_name as name, table_type as type from information_schema.tables @@ -55,14 +55,18 @@ export default class Mysql extends Base { return rows.map(row => zipObject(fields, row)); } - async fetchTableSummary({ name }) { + async fetchTableSummary({ + name + }: { + name: string; + }): Promise<{ name: string; defs: { fields: string[]; rows: (string | null)[][] }; schema?: string }> { const sql = "show columns from ??"; const defs = await this._execute(sql, name); return { name, defs }; } - _execute(query, ...args): Promise { + _execute(query: string, ...args): Promise { if (this.currentConnection) { return Promise.reject(new Error("A query is running")); } @@ -94,7 +98,7 @@ export default class Mysql extends Base { }); } - descriptionTable() { + descriptionTable(): string { return Util.stripHeredoc(` |host|${this.config.host}| |port|${this.config.port}| diff --git a/src/lib/DataSourceDefinition/Postgres.ts b/src/lib/DataSourceDefinition/Postgres.ts index 51f8fc2a..6b2bc7a6 100644 --- a/src/lib/DataSourceDefinition/Postgres.ts +++ b/src/lib/DataSourceDefinition/Postgres.ts @@ -1,5 +1,5 @@ import pg from "pg"; -import Base from "./Base"; +import Base, { ConfigSchemaType } from "./Base"; import Util from "../Util"; import { zipObject } from "lodash"; @@ -50,13 +50,13 @@ import { zipObject } from "lodash"; export default class Postgres extends Base { currentClient: any; - static get key() { + static get key(): string { return "postgres"; } - static get label() { + static get label(): string { return "PostgreSQL"; } - static get configSchema() { + static get configSchema(): ConfigSchemaType { return [ { name: "host", label: "Host", type: "string", placeholder: "localhost" }, { name: "port", label: "Port", type: "number", placeholder: 5432 }, @@ -72,7 +72,7 @@ export default class Postgres extends Base { ]; } - async execute(query, options: any = {}) { + async execute(query: string, options: any = {}): Promise { try { return await this._execute(query); } catch (err) { @@ -80,19 +80,19 @@ export default class Postgres extends Base { } } - cancel() { + cancel(): Promise { const pid = this.currentClient && this.currentClient.processID; if (!pid) return Promise.resolve(); return new Postgres(this.config)._execute(`select pg_cancel_backend(${pid})`); } - async connectionTest() { + async connectionTest(): Promise { await this._execute("select 1"); return true; } - async fetchTables() { + async fetchTables(): Promise<{ name: string; type: string; schema?: string }[]> { const query = Util.stripHeredoc(` select table_schema as schema, table_name as name, table_type as type from information_schema.tables @@ -104,7 +104,13 @@ export default class Postgres extends Base { return rows.map(row => zipObject(fields, row)); } - async fetchTableSummary({ schema, name }) { + async fetchTableSummary({ + schema, + name + }: { + schema: string; + name: string; + }): Promise<{ name: string; defs: { fields: string[]; rows: (string | null)[][] }; schema?: string }> { const query = Util.stripHeredoc(` select pg_attribute.attname as name, @@ -130,7 +136,7 @@ export default class Postgres extends Base { return { schema, name, defs }; } - descriptionTable() { + descriptionTable(): string { return Util.stripHeredoc(` |host|${this.config.host}| |port|${this.config.port}| diff --git a/src/lib/DataSourceDefinition/SQLite3.ts b/src/lib/DataSourceDefinition/SQLite3.ts index 37dec962..ec8e5534 100644 --- a/src/lib/DataSourceDefinition/SQLite3.ts +++ b/src/lib/DataSourceDefinition/SQLite3.ts @@ -1,46 +1,50 @@ import sqlite3 from "sqlite3"; -import Base from "./Base"; +import Base, { ConfigSchemaType } from "./Base"; import Util from "../Util"; export default class SQLite3 extends Base { db: sqlite3.Database | null; - static get key() { + static get key(): string { return "sqlite3"; } - static get label() { + static get label(): string { return "SQLite3"; } - static get configSchema() { + static get configSchema(): ConfigSchemaType { return [{ name: "path", label: "Path", type: "string", placeholder: "/path/to/db.sqlite3" }]; } - execute(query) { + execute(query: string) { return this._execute(query); } - async cancel() { + cancel(): void { this.db.interrupt(); } - async fetchTables() { + async fetchTables(): Promise<{ name: string; type: string; schema?: string }[]> { const { rows }: any = await this._execute("select tbl_name from sqlite_master where type = 'table'"); return rows.map(row => { return { name: row[0], type: "table" }; }); } - async fetchTableSummary({ name }) { + async fetchTableSummary({ + name + }: { + name: string; + }): Promise<{ name: string; defs: { fields: string[]; rows: (string | null)[][] }; schema?: string }> { const defs = await this._execute(`pragma table_info(${name})`); return { name, defs }; } - async connectionTest() { + async connectionTest(): Promise { return this._execute("select 1"); } - _execute(query) { + _execute(query: string): Promise { this.db = new sqlite3.Database(this.config.path); return new Promise((resolve, reject) => { this.db.all(query, (err, results) => { @@ -59,7 +63,7 @@ export default class SQLite3 extends Base { }); } - descriptionTable() { + descriptionTable(): string { return Util.stripHeredoc(` |path|${this.config.path}| `); diff --git a/src/lib/DataSourceDefinition/TreasureData.ts b/src/lib/DataSourceDefinition/TreasureData.ts index 1b34ca3f..1fe1862f 100644 --- a/src/lib/DataSourceDefinition/TreasureData.ts +++ b/src/lib/DataSourceDefinition/TreasureData.ts @@ -1,5 +1,5 @@ import TD from "td"; -import Base from "./Base"; +import Base, { ConfigSchemaType } from "./Base"; import Util from "../Util"; const WAIT_INTERVAL = 2000; @@ -11,13 +11,13 @@ export default class TreasureData extends Base { _cancel: any; _client: any; - static get key() { + static get key(): string { return "treasuredata"; } - static get label() { + static get label(): string { return "TreasureData"; } - static get configSchema() { + static get configSchema(): ConfigSchemaType { return [ { name: "database", label: "Database", type: "string", required: true }, { @@ -37,7 +37,7 @@ export default class TreasureData extends Base { ]; } - execute(query) { + execute(query: string): Promise { if (this.jobId) { return Promise.reject(new Error("A query is running")); } @@ -68,7 +68,7 @@ export default class TreasureData extends Base { }); } - cancel() { + cancel(): void { this._cancel && this._cancel(); this.kill(); } @@ -80,12 +80,12 @@ export default class TreasureData extends Base { }); } - async connectionTest() { + async connectionTest(): Promise { await this._execQuery("select 1"); return true; } - fetchTables() { + fetchTables(): Promise<{ name: string; type: string; schema?: string }[]> { return new Promise((resolve, reject) => { return this.client.listTables(this.config.database, (err, list) => { if (err) { @@ -98,14 +98,16 @@ export default class TreasureData extends Base { }); } - async fetchTableSummary({ name }) { + async fetchTableSummary({ + name + }): Promise<{ name: string; defs: { fields: string[]; rows: (string | null)[][] }; schema?: string }> { const table = cacheTableList.tables.find(t => t.name === name); const fields = ["column", "type"]; const rows = JSON.parse(table.schema); return { name, defs: { fields, rows } }; } - descriptionTable() { + descriptionTable(): string { return Util.stripHeredoc(` |database|${this.config.database}| |queryType|${this.config.queryType}| diff --git a/src/lib/Util/stripHeredoc.ts b/src/lib/Util/stripHeredoc.ts index b10877f9..00bcf45a 100644 --- a/src/lib/Util/stripHeredoc.ts +++ b/src/lib/Util/stripHeredoc.ts @@ -1,4 +1,4 @@ -export default function stripHeredoc(str) { +export default function stripHeredoc(str: string) { str = str.trim(); const margins = (str.match(/^ +/gm) || []).map(s => s.length); const margin = Math.min(...margins);