import { Timezone } from "chronoshift" ; import { Expression , Datum , PlywoodValue , Dataset , Set , SQLParse , TimeRange } from "plywood" ; import { getVariablesFlatDataset } from './variables' ; import { columnToMySQL , dateToSQL , createMySQLGateway , fallbackMySQLFactory , MySQLParameters } from './mysql-gateway' ; import { executeSQLParse } from "./plyql-executor" ; function printError ( sql , err ) { console . log ( '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' ) ; console . log ( 'Failed to resolve query with Plywood.' ) ; console . log ( 'Query:' ) ; console . log ( sql ) ; console . log ( 'If you believe this query should work please create an issue on PlyQL and include this section' ) ; console . log ( 'Issue url: https://github.com/implydata/plyql/issues' ) ; console . log ( 'Message:' ) ; console . log ( err . message ) ; console . log ( 'Stack:' ) ; console . log ( ( err as any ) . stack ) ; console . log ( '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' ) ; } function datumToMySQLRow ( row , timezone ) { let newRow = { } ; for ( let k in row ) { let v = row [ k ] ; if ( v && ( v as any ) . start ) v = ( v as any ) . start ; if ( v && ( v as any ) . toISOString ) { v = dateToSQL ( v as Date , timezone ) ; } else if ( Set . isSet ( v ) || TimeRange . isTimeRange ( v ) ) { v = v . toString ( timezone ) ; } else if ( typeof v === 'boolean' ) { v = Number ( v ) ; } newRow [ k ] = v ; } return newRow ; } export function plyqlMySQLGateway ( port , context , timezone , fallbackURI ) { createMySQLGateway ( port , ( parameters , conn ) : void => { let { sql , connectionId } = parameters ; let myContext = context ; let match ; if ( ( /SELECT\s+@@/i ) . test ( sql ) ) { sql = sql . replace ( /@@(?:global\.|session\.)?/g , '' ) ; myContext = { data : getVariablesFlatDataset ( ) } ; } if ( match = sql . match ( /USE\s+`/i ) ) { sql = "SET NAMES 'utf8'" ; } if ( match = sql . match ( /SELECT\s+(CONNECTION_ID\(\s*\))/i ) ) { let name = match [ 1 ] ; let row = { } ; row [ name ] = connectionId ; conn . writeTextResult ( [ row ] , [ { catalog : 'def' , schema : '' , name : 'CONNECTION_ID()' , orgName : 'CONNECTION_ID()' , table : '' , orgTable : '' , characterSet : 33 , columnLength : 500 , columnType : 0x8 , flags : 32896 , decimals : 0 } ] ) ; return ; } let sqlParse ; try { sqlParse = Expression . parseSQL ( sql ) ; } catch ( e ) { printError ( sql , e ) ; conn . writeError ( { code : 1064 , message : e . message } ) ; return ; } if ( ! sqlParse . verb ) { conn . writeError ( { code : 1064 , message : `Must have a verb` } ) ; return ; } switch ( sqlParse . verb ) { case 'SET' : conn . writeOk ( ) ; return ; case 'SELECT' : executeSQLParse ( sqlParse , myContext , timezone ) . then ( ( dataset ) => { if ( Dataset . isDataset ( dataset ) ) { let flatDataset = dataset . flatten ( ) ; let plyColumns = flatDataset . attributes . map ( c => columnToMySQL ( c , sqlParse . table ) ) ; let plyRows = flatDataset . data . map ( ( d ) => datumToMySQLRow ( d , timezone ) ) ; conn . writeTextResult ( plyRows , plyColumns ) ; } else { throw new Error ( 'unexpected result from expression' ) ; } } ) ; return ; default : conn . writeError ( { code : 1337 , message : `Permission to ${ sqlParse . verb } denied` } ) ; return ; } } ) ; }