@enzedd/stimulsoft-clickhouse-data-adapter
Version:
Stimulsoft clickhouse data adapter
143 lines (130 loc) • 4.73 kB
JavaScript
/*
Stimulsoft.Reports.JS Clickhouse adapter
*/
require('isomorphic-fetch');
const ADAPTER_VERSION = "2022.3.1";
const CLICKHOUSE_TO_JS_TYPES = {
// Possible js values: string, number, int, boolean, array, datetime, datetimeZ, time, timeZ, datetimeoffset
'Array': 'array',
'Bool': 'boolean',
'IPv6': 'string',
'IPv4': 'string',
'Enum': 'string',
'FixedString': 'string',
'String': 'string',
'Float64': 'number',
'UInt8': 'int',
'UInt16': 'int',
'DateTime': 'datetime',
'DateTime64': 'datetime',
'Decimal': 'number',
'Int64': 'int',
'Float32': 'number',
'UInt64': 'int',
'UInt32': 'int',
'Int16': 'int',
'Int32': 'int',
'Int8': 'int',
'UUID': 'string',
}
let DEFAULT_TYPE = 'string';
class ClickhouseClient {
constructor(params) {
this.protocol = params.protocol || (params.port && params.port === 8443) ? 'https' : 'http'
this.host = params.host || 'localhost'
this.port = params.port || (params.protocol && params.protocol === 'https') ? 8443 : 8123
this.database = params.database || 'default'
this.user = params.user || 'default'
this.password = params.password || ''
}
static getConnectionParams(connectionString) {
const params = {};
for (let propertyIndex in connectionString.split(";")) {
let property = connectionString.split(";")[propertyIndex];
if (property) {
let match = property.split(new RegExp('=|:'));
if (match && match.length >= 2) {
match[0] = match[0].trim().toLowerCase();
match[1] = match[1].trim();
switch (match[0]) {
case "data source":
case "server":
case "host":
params["host"] = match[1];
break;
case "port":
params["port"] = match[1];
break;
case "database":
case "location":
params["database"] = match[1];
break;
case "uid":
case "user":
case "user id":
params["user"] = match[1];
break;
case "pwd":
case "password":
params["password"] = match[1];
break;
case "ssl":
params["protocol"] = match[1] ? 'https' : 'http';
break;
case "sslmode":
if (match[1] === "require") params["protocol"] = 'https';
else if (match[1] === "disable") params["protocol"] = 'http';
break;
}
}
}
}
return params;
};
getColumnType(val) {
val = val.split('(')[0];
return CLICKHOUSE_TO_JS_TYPES[val] || DEFAULT_TYPE
}
query(sql) {
return fetch(`http://${this.host}:${this.port}?database=${this.database}&query=${sql} FORMAT JSONCompact`, {
headers: {
"X-Clickhouse-User": this.user,
"X-Clickhouse-Key": this.password,
}
}).then(response => {
return response.json()
}).then(data => {
const columns = data.meta.map(item => item.name);
const types = data.meta.map(item => this.getColumnType(item.type));
return {
success: true,
columns: columns,
rows: data.data,
types: types,
};
}).catch(error => {
console.error('There has been an issue with your fetch operation:', error)
return {
success: false,
notice: error.message,
}
});
}
}
exports.process = function (command, onResult) {
try {
const connectionParams = ClickhouseClient.getConnectionParams(command.connectionString);
const client = new ClickhouseClient(connectionParams)
client.query(command.queryString).then(result => {
result.adapterVersion = ADAPTER_VERSION;
onResult(result)
})
} catch (error) {
console.error('Failed to process:', error)
onResult({
success: false,
notice: error.stack,
adapterVersion: ADAPTER_VERSION,
})
}
}