@vulcan-sql/extension-driver-ksqldb
Version:
ksqlDB driver for VulcanSQL
105 lines • 4.77 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.KSQLDBDataSource = void 0;
const tslib_1 = require("tslib");
const core_1 = require("@vulcan-sql/core");
const stream_1 = require("stream");
const sqlBuilder_1 = require("./sqlBuilder");
const typeMapper_1 = require("./typeMapper");
const restfulClient_1 = require("./restfulClient");
let KSQLDBDataSource = class KSQLDBDataSource extends core_1.DataSource {
constructor() {
super(...arguments);
this.logger = this.getLogger();
this.clientMapping = new Map();
}
onActivate() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const profiles = this.getProfiles().values();
for (const profile of profiles) {
this.logger.debug(`Initializing profile: ${profile.name} using ksqldb driver`);
const options = Object.assign({}, profile.connection);
const client = new restfulClient_1.RestfulClient(options);
this.clientMapping.set(profile.name, { client, options });
// Testing connection
const isRunning = yield client.checkConnectionRunning();
if (!isRunning) {
throw new Error('KsqlDb server is not running');
}
this.logger.debug(`Profile ${profile.name} initialized`);
}
});
}
prepare({ parameterIndex }) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
return `$${parameterIndex}`;
});
}
execute({ statement: sql, bindParams, profileName, operations, }) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
this.checkProfileExist(profileName);
const { client } = this.clientMapping.get(profileName);
const params = Object.fromEntries(bindParams);
try {
const builtSQL = (0, sqlBuilder_1.buildSQL)(sql, operations);
const data = yield client.query({
query: builtSQL,
query_params: params,
});
return yield this.getResultFromRestfulResponse(data);
}
catch (e) {
this.logger.debug(`Errors occurred, release connection from ${profileName}`);
throw e;
}
});
}
getResultFromRestfulResponse(data) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const dataRowStream = new stream_1.Stream.Readable({
objectMode: true,
read: () => null,
// automatically destroy() the stream when it emits 'finish' or errors. Node > 10.16
autoDestroy: true,
});
const headerData = data[0].header;
const columns = (0, sqlBuilder_1.convertSchemaToColumns)(headerData.schema);
// add the data row to the stream
for (const innerData of data) {
// format the ksqldb table response to VulcanSQL Data API
// https://docs.ksqldb.io/en/latest/developer-guide/ksqldb-rest-api/query-endpoint/#example-table-response
if (innerData.row) {
const rowColumns = innerData.row.columns;
const outputData = rowColumns.reduce((result, value, index) => {
return Object.assign(Object.assign({}, result), { [columns[index].name]: value });
}, {});
dataRowStream.push(outputData);
}
// the end of query result
if (innerData.finalMessage) {
dataRowStream.push(null);
}
}
return {
getColumns: () => {
return columns.map((column) => ({
name: column.name || '',
// Convert KsqlDb type to FieldDataType supported by VulcanSQL for generating the response schema in the specification, see: https://github.com/Canner/vulcan-sql/pull/78#issuecomment-1621532674
type: (0, typeMapper_1.mapFromKsqlDbType)(column.type || ''),
}));
},
getData: () => dataRowStream,
};
});
}
checkProfileExist(profileName) {
if (!this.clientMapping.has(profileName)) {
throw new core_1.InternalError(`Profile instance ${profileName} not found`);
}
}
};
KSQLDBDataSource = tslib_1.__decorate([
(0, core_1.VulcanExtensionId)('ksqldb')
], KSQLDBDataSource);
exports.KSQLDBDataSource = KSQLDBDataSource;
//# sourceMappingURL=ksqldbDataSource.js.map