/** * @NApiVersion 2.1 * @NScriptType Suitelet * @NModuleScope Public */ define(['N/file', 'N/https', 'N/log', 'N/query', 'N/record', 'N/render', 'N/runtime', 'N/ui/serverWidget', 'N/url'], initializeScriptModulesAndSetEntryPoint); var file, https, log, query, record, render, runtime, scriptURL, url, version = '2025.1-Moss-Stable_version'; var datatablesEnabled = true, remoteLibraryEnabled = true, rowsReturnedDefault = 50, queryFolderID = null, workbooksEnabled = false; function initializeScriptModulesAndSetEntryPoint(fileModule, httpsModule, logModule, queryModule, recordModule, renderModule, runtimeModule, serverWidgetModule, urlModule) { file = fileModule; https = httpsModule; log = logModule; query = queryModule; record = recordModule; render = renderModule; runtime = runtimeModule; serverWidget = serverWidgetModule; url = urlModule; return { onRequest: function (context) { scriptURL = url.resolveScript({ scriptId: runtime.getCurrentScript().id, deploymentId: runtime.getCurrentScript().deploymentId, returnExternalURL: false }); if (context.request.method == 'POST') { handlePostRequest(context); } else { handleGetRequest(context); } } } } function handleGetRequest(context) { if (context.request.parameters.hasOwnProperty('function')) { if (context.request.parameters['function'] == 'tablesReference') { generateTablesReferencePageHtml(context); } if (context.request.parameters['function'] == 'documentGenerate') { generateDocumentFromQueryResults(context); } } else { var form = serverWidget.createForm({ title: `SuiteQL Query Tool`, hideNavBar: true }); var htmlField = form.addField({ id: 'custpage_field_html', type: serverWidget.FieldType.INLINEHTML, label: 'HTML' }); htmlField.defaultValue = generateMainToolInterfaceHtml(); context.response.writePage(form); } } function handlePostRequest(context) { context.response.setHeader('Content-Type', 'application/json'); var requestPayload; try { requestPayload = JSON.parse(context.request.body); } catch (e) { log.error({ title: 'FATAL: Failed to parse request body', details: 'Body received: ' + context.request.body }); context.response.write(JSON.stringify({ 'error': { message: 'Invalid request from client. Could not parse JSON body. See execution log for details.' } })); return; } switch (requestPayload['function']) { case 'documentSubmit': return storeDocumentInfoInSessionForGeneration(context, requestPayload); case 'queryExecute': return executeQueryAndReturnResults(context, requestPayload); case 'sqlFileExists': return checkIfSqlFileExistsInLocalLibrary(context, requestPayload); case 'sqlFileLoad': return loadSqlFileFromLocalLibrary(context, requestPayload); case 'sqlFileSave': return saveSqlFileToLocalLibrary(context, requestPayload); case 'localLibraryFilesGet': return getLocalQueryLibraryFiles(context); case 'workbookLoad': return loadQueryFromWorkbook(context, requestPayload); case 'workbooksGet': return getListOfAvailableWorkbooks(context); default: log.error({ title: 'Payload - Unsupported Function', details: requestPayload['function'] }); } } function generateDocumentFromQueryResults(context) { try { var sessionScope = runtime.getCurrentSession(); var docInfo = JSON.parse(sessionScope.get({ name: 'suiteQLDocumentInfo' })); var moreRecords = true; var pagatedRowBegin = docInfo.rowBegin; var paginatedRowEnd = docInfo.rowEnd; var queryParams = new Array(); var records = new Array(); do { var paginatedSQL = 'SELECT * FROM ( SELECT ROWNUM AS ROWNUMBER, * FROM (' + docInfo.query + ' ) ) WHERE ( ROWNUMBER BETWEEN ' + paginatedRowBegin + ' AND ' + paginatedRowEnd + ')'; var queryResults = query.runSuiteQL({ query: paginatedSQL, params: queryParams }).asMappedResults(); records = records.concat(queryResults); if (queryResults.length < 5000) { moreRecords = false; } paginatedRowBegin = paginatedRowBegin + 5000; } while (moreRecords); var recordsDataSource = { 'records': records }; var renderer = render.create(); renderer.addCustomDataSource({ alias: 'results', format: render.DataSource.OBJECT, data: recordsDataSource }); renderer.templateContent = docInfo.template; if (docInfo.docType == 'pdf') { let renderObj = renderer.renderAsPdf(); let pdfString = renderObj.getContents(); context.response.setHeader('Content-Type', 'application/pdf'); context.response.write(pdfString); } else { let htmlString = renderer.renderAsString(); context.response.setHeader('Content-Type', 'text/html'); context.response.write(htmlString); } } catch (e) { log.error({ title: 'generateDocumentFromQueryResults Error', details: e }); context.response.write('Error: ' + e); } } function storeDocumentInfoInSessionForGeneration(context, requestPayload) { try { var responsePayload; var sessionScope = runtime.getCurrentSession(); sessionScope.set({ name: 'suiteQLDocumentInfo', value: JSON.stringify(requestPayload) }); responsePayload = { 'submitted': true } } catch (e) { log.error({ title: 'storeDocumentInfoInSessionForGeneration Error', details: e }); responsePayload = { 'error': e } } context.response.write(JSON.stringify(responsePayload, null, 5)); } function executeQueryAndReturnResults(context, requestPayload) { try { var responsePayload; var moreRecords = true; var records = new Array(); var totalRecordCount = 0; var queryParams = new Array(); var paginatedRowBegin = requestPayload.rowBegin; var paginatedRowEnd = requestPayload.rowEnd; var nestedSQL = requestPayload.query + "\n"; if ((requestPayload.viewsEnabled) && (queryFolderID !== null)) { var pattern = /(?:^|\s)\#(\w+)\b/ig; var views = nestedSQL.match(pattern); if ((views !== null) && (views.length > 0)) { for (let i = 0; i < views.length; i++) { view = views[i].replace(/\s+/g, ''); viewFileName = view.substring(1, view.length) + '.sql'; var sql = 'SELECT ID FROM File WHERE ( Folder = ? ) AND ( Name = ? )'; var queryResults = query.runSuiteQL({ query: sql, params: [queryFolderID, viewFileName] }); var files = queryResults.asMappedResults(); if (files.length == 1) { var fileObj = file.load({ id: files[0].id }); nestedSQL = nestedSQL.replace(view, '( ' + fileObj.getContents() + ' ) AS ' + view.substring(1, view.length)); } else { throw { 'name:': 'UnresolvedViewException', 'message': 'Unresolved View ' + viewFileName } } } } } let beginTime = new Date().getTime(); if (requestPayload.paginationEnabled) { do { var paginatedSQL = 'SELECT * FROM ( SELECT ROWNUM AS ROWNUMBER, * FROM ( ' + nestedSQL + ' ) ) WHERE ( ROWNUMBER BETWEEN ' + paginatedRowBegin + ' AND ' + paginatedRowEnd + ')'; var queryResults = query.runSuiteQL({ query: paginatedSQL, params: queryParams }).asMappedResults(); records = records.concat(queryResults); if (queryResults.length < 5000) { moreRecords = false; } paginatedRowBegin = paginatedRowBegin + 5000; } while (moreRecords); } else { records = query.runSuiteQL({ query: nestedSQL, params: queryParams }).asMappedResults(); } let elapsedTime = (new Date().getTime() - beginTime); responsePayload = { 'records': records, 'elapsedTime': elapsedTime } if (requestPayload.returnTotals) { if (records.length > 0) { var paginatedSQL = 'SELECT COUNT(*) AS TotalRecordCount FROM ( ' + nestedSQL + ' )'; var queryResults = query.runSuiteQL({ query: paginatedSQL, params: queryParams }).asMappedResults(); responsePayload.totalRecordCount = queryResults[0].totalrecordcount; } } } catch (e) { log.error({ title: 'executeQueryAndReturnResults Error', details: e }); responsePayload = { 'error': e } } context.response.write(JSON.stringify(responsePayload, null, 5)); } function getLocalQueryLibraryFiles(context) { var responsePayload; var sql = ` SELECT ID, Name, Description FROM File WHERE ( Folder = ? ) ORDER BY Name `; var queryResults = query.runSuiteQL({ query: sql, params: [queryFolderID] }); var records = queryResults.asMappedResults(); if (records.length > 0) { responsePayload = { 'records': records }; } else { responsePayload = { 'error': 'No SQL Files' }; } context.response.write(JSON.stringify(responsePayload, null, 5)); } function checkIfSqlFileExistsInLocalLibrary(context, requestPayload) { var responsePayload; var sql = ` SELECT ID FROM File WHERE ( Folder = ? ) AND ( Name = ? ) `; var queryResults = query.runSuiteQL({ query: sql, params: [queryFolderID, requestPayload.filename] }); var records = queryResults.asMappedResults(); if (records.length > 0) { responsePayload = { 'exists': true }; } else { responsePayload = { 'exists': false }; } context.response.write(JSON.stringify(responsePayload, null, 5)); } function loadSqlFileFromLocalLibrary(context, requestPayload) { var responsePayload; try { var fileObj = file.load({ id: requestPayload.fileID }); responsePayload = {} responsePayload.file = fileObj; responsePayload.sql = fileObj.getContents(); } catch (e) { log.error({ title: 'loadSqlFileFromLocalLibrary Error', details: e }); responsePayload = { 'error': e } } context.response.write(JSON.stringify(responsePayload, null, 5)); } function saveSqlFileToLocalLibrary(context, requestPayload) { var responsePayload; try { var fileObj = file.create({ name: requestPayload.filename, contents: requestPayload.contents, description: requestPayload.description, fileType: file.Type.PLAINTEXT, folder: queryFolderID, isOnline: false }); var fileID = fileObj.save(); responsePayload = {} responsePayload.fileID = fileID; } catch (e) { log.error({ title: 'saveSqlFileToLocalLibrary Error', details: e }); responsePayload = { 'error': e } } context.response.write(JSON.stringify(responsePayload, null, 5)); } function loadQueryFromWorkbook(context, requestPayload) { var responsePayload; try { var loadedQuery = query.load({ id: requestPayload.scriptID }); responsePayload = {} responsePayload.sql = loadedQuery.toSuiteQL().query; } catch (e) { log.error({ title: 'loadQueryFromWorkbook Error', details: e }); responsePayload = { 'error': e } } context.response.write(JSON.stringify(responsePayload, null, 5)); } function getListOfAvailableWorkbooks(context) { var responsePayload; var sql = ` SELECT ScriptID, Name, Description, BUILTIN.DF( Owner ) AS Owner FROM UsrSavedSearch ORDER BY Name `; var queryResults = query.runSuiteQL({ query: sql, params: [] }); var records = queryResults.asMappedResults(); if (records.length > 0) { responsePayload = { 'records': records }; } else { responsePayload = { 'error': 'No Workbooks' }; } context.response.write(JSON.stringify(responsePayload, null, 5)); } function generateMainToolInterfaceHtml() { return ` SuiteQL Query Tool
menu settings
Result Format
NULL Display
${generateLocalLibraryLoadModalHtml()} ${generateRemoteLibraryLoadModalHtml()} ${generateRecentQueriesModalHtml()} ${generateSaveQueryModalHtml()} ${generateWorkbooksModalHtml()} `; } function generateTablesReferencePageHtml(context) { var form = serverWidget.createForm({ title: 'SuiteQL Tables Reference', hideNavBar: false }); var htmlField = form.addField({ id: 'custpage_field_html', type: serverWidget.FieldType.INLINEHTML, label: 'HTML' }); htmlField.defaultValue = `
Tables
Loading...
Details
Select a table to view its details.
`; context.response.writePage(form); } function generateLocalLibraryLoadModalHtml() { return ``; } function generateRemoteLibraryLoadModalHtml() { return ``; } function generateRecentQueriesModalHtml() { return ``; } function generateSaveQueryModalHtml() { return `