import { createConnection , IConnection } from 'vscode-languageserver' ; import * as fs from 'fs' ; export class OracleConnection { private static _connection : IConnection ; private static _oracleDB ; private static _oracleConnection ; private static _customID = 0 ; private static _customConnections = { } ; private static ORACLE_DB_VERSION = 'oracledb@"^3.0.0"' ; public static init ( ) { this . _connection = createConnection ( ) ; [ { name : 'Oracle/install' , fn : this . installOracle } , { name : 'Oracle/init' , fn : this . initOracle } , { name : 'Oracle/connect' , fn : this . connect } , { name : 'Oracle/disconnect' , fn : this . disconnect } , { name : 'Oracle/execCommand' , fn : this . execCommand } ] . forEach ( request => { this . _connection . onRequest ( request . name , ( params ) => request . fn . call ( this , params ) ) ; } ) ; this . _connection . listen ( ) ; } private static createOracleDirectory ( ) { return new Promise < any > ( ( resolve , reject ) => { const directory = '../node_modules/oracledb' ; fs . stat ( directory , ( err , stats ) => { if ( ! err ) return resolve ( false ) ; if ( err . code === 'ENOENT' ) { fs . mkdir ( directory , error => { if ( error ) return reject ( 'OracleDB failed create directory ' + error ) ; return resolve ( true ) ; } ) ; } else return reject ( 'OracleDB failed check directory ' + err ) ; } ) ; } ) ; } private static installOracle ( ) { return new Promise < any > ( ( resolve , reject ) => { this . createOracleDirectory ( ) . then ( install => { if ( ! install ) return resolve ( 'OracleDB already installed' ) ; this . _connection . sendNotification ( 'Oracle/install' , `Start install ${ OracleConnection . ORACLE_DB_VERSION }...` ) ; require ( 'child_process' ) . exec ( `npm install ${ OracleConnection . ORACLE_DB_VERSION }` , ( err , stdout , stderr ) => { this . _connection . sendNotification ( 'Oracle/install' , `...End install ${ OracleConnection . ORACLE_DB_VERSION }` ) ; if ( err ) resolve ( { error : err } ) ; if ( stderr ) resolve ( { stderror : stderr } ) ; resolve ( { install : stdout } ) ; } ) ; } ) ; } ) ; } private static initOracle ( ) { return new Promise < any > ( ( resolve , reject ) => { try { this . _oracleDB = require ( 'oracledb' ) ; this . _oracleDB . fetchAsString = [ this . _oracleDB . CLOB ] ; return resolve ( 'oracleDB work' ) ; } catch ( e ) { return resolve ( { error : 'oracleDB failed: ' + e + 'ENV: ' + process . env } ) ; } } ) ; } private static execCommand ( params ) { return new Promise < any > ( ( resolve , reject ) => { if ( ! this . _oracleDB ) return resolve ( { error : 'OracleDB is missing' } ) ; if ( ! ( params && params . connection ) && ! this . _oracleConnection ) return resolve ( { error : 'Connection is missing' } ) ; this . internalExecCommand ( params ) . then ( data => resolve ( data ) ) . catch ( err => resolve ( err ) ) ; } ) ; } private static internalExecCommand ( params ) { return new Promise < any > ( ( resolve , reject ) => { const cmd = params . sql . trim ( ) . toLowerCase ( ) ; let internalConnection ; if ( params . connection ) { internalConnection = this . _customConnections [ params . connection . customID ] ; if ( ! internalConnection ) return reject ( { params : params , error : 'connection not found ' , list : this . _customConnections , connection : internalConnection } ) ; } else internalConnection = this . _oracleConnection ; if ( cmd === 'commit' || cmd === 'rollback' ) internalConnection [ cmd ] ( ) . then ( ( ) => resolve ( { data : cmd } ) ) . catch ( err => reject ( { error : this . formatOracleError ( err ) } ) ) ; else { params . params = params . params || { } ; params . opt = params . opt || { } ; internalConnection . execute ( params . sql , params . params , params . opt ) . then ( result => resolve ( { params : params , data : result } ) ) . catch ( err => reject ( { params : params , error : this . formatOracleError ( err ) } ) ) ; } } ) ; } private static connect ( params ) { return new Promise < any > ( ( resolve , reject ) => { if ( ! this . _oracleDB ) return resolve ( { error : 'OracleDB is missing' } ) ; const result = { } ; Promise . resolve ( ) . then ( ( ) => { if ( params && ! params . custom && this . _oracleConnection ) return this . disconnect ( ) ; return ; } ) . then ( ( data ) => { if ( data && data . error ) result . disconnect = data ; return this . internalConnect ( params ) ; } ) . then ( connection => { if ( params . custom ) { connection . customID = ++ this . _customID ; this . _customConnections [ connection . customID ] = connection ; } else this . _oracleConnection = connection ; result . connection = connection ; result . connected = true ; if ( params . schema ) result . schema = params . schema ; if ( ! params . loginScript ) return ; else return this . internalExecConnectCommand ( params ) ; } ) . then ( data => { if ( data ) result . loginScript = data ; return resolve ( result ) ; } ) . catch ( err => { result . error = err ; return resolve ( result ) ; } ) ; } ) ; } private static internalConnect ( params ) { return new Promise < any > ( ( resolve , reject ) => { if ( ! params ) return reject ( 'No params !' ) ; const connectParams = { user : params . user || params . username , password : params . password || params . username , connectString : params . connectString || params . database , privilege : this . _oracleDB [ params . privilege ] } ; this . _oracleDB . getConnection ( connectParams , ( err , connection ) => { if ( err ) return reject ( { error : this . formatOracleError ( err ) , params : connectParams } ) ; return resolve ( connection ) ; } ) ; } ) ; } private static internalExecConnectCommand ( params ) { return new Promise < any > ( ( resolve , reject ) => { this . internalExecCommand ( { sql : params . loginScript } ) . then ( data => resolve ( data ) ) . catch ( err => resolve ( err ) ) ; } ) ; } private static disconnect ( params ? ) { return new Promise < any > ( ( resolve , reject ) => { let internalConnection ; if ( params && params . connection ) { internalConnection = this . _customConnections [ params . connection . customID ] ; if ( ! internalConnection ) return resolve ( { params : params , error : 'connection not found' } ) ; } else { if ( ! this . _oracleConnection ) return resolve ( true ) ; internalConnection = this . _oracleConnection ; } internalConnection . close ( err => { if ( err ) return resolve ( { error : err } ) ; if ( params && params . connection ) delete this . _customConnections [ params . connection . customID ] ; else delete this . _oracleConnection ; return resolve ( true ) ; } ) ; } ) ; } private static formatOracleError ( error ) { return { message : error . message , num : error . errorNum , offset : error . offset } ; } } { OracleConnection . init ( ) ; }