(query)
| 2 | Creating a Query Parser which can parse SQL `SELECT` Queries only. |
| 3 | // */ |
| 4 | function parseSelectQuery(query) { |
| 5 | try { |
| 6 | |
| 7 | // Trim the query to remove any leading/trailing whitespaces |
| 8 | query = query.trim(); |
| 9 | |
| 10 | // Initialize distinct flag |
| 11 | let isDistinct = false; // Global DISTINCT, not within COUNT |
| 12 | let isCountDistinct = false; // New flag for DISTINCT within COUNT |
| 13 | let distinctFields = []; // Array to hold fields after DISTINCT within COUNT or APPROXIMATE_COUNT |
| 14 | |
| 15 | |
| 16 | // Detect APPROXIMATE_COUNT |
| 17 | let isApproximateCount = false; |
| 18 | const approximateCountRegex = /APPROXIMATE_COUNT\((DISTINCT\s)?(.+?)\)/i; |
| 19 | const approximateCountMatch = query.match(approximateCountRegex); |
| 20 | if (approximateCountMatch) { |
| 21 | isApproximateCount = true; |
| 22 | // If DISTINCT is used within APPROXIMATE_COUNT, capture the fields |
| 23 | if (approximateCountMatch[1]) { |
| 24 | isCountDistinct = true; |
| 25 | // distinctFields.push(approximateCountMatch[2].trim()); |
| 26 | } |
| 27 | // Simplify further processing by normalizing to COUNT (adjust as necessary for your logic) |
| 28 | query = query.replace(approximateCountRegex, `COUNT(${approximateCountMatch[1] || ''}${approximateCountMatch[2]})`); |
| 29 | } |
| 30 | |
| 31 | // Check for DISTINCT keyword and update the query |
| 32 | if (query.toUpperCase().includes('SELECT DISTINCT')) { |
| 33 | isDistinct = true; |
| 34 | query = query.replace('SELECT DISTINCT', 'SELECT'); |
| 35 | } |
| 36 | |
| 37 | // Updated regex to capture LIMIT clause and remove it for further processing |
| 38 | const limitRegex = /\sLIMIT\s(\d+)/i; |
| 39 | const limitMatch = query.match(limitRegex); |
| 40 | |
| 41 | let limit = null; |
| 42 | if (limitMatch) { |
| 43 | limit = parseInt(limitMatch[1], 10); |
| 44 | query = query.replace(limitRegex, ''); // Remove LIMIT clause |
| 45 | } |
| 46 | |
| 47 | // Process ORDER BY clause and remove it for further processing |
| 48 | const orderByRegex = /\sORDER BY\s(.+)/i; |
| 49 | const orderByMatch = query.match(orderByRegex); |
| 50 | let orderByFields = null; |
| 51 | if (orderByMatch) { |
| 52 | orderByFields = orderByMatch[1].split(',').map(field => { |
| 53 | const [fieldName, order] = field.trim().split(/\s+/); |
| 54 | return { fieldName, order: order ? order.toUpperCase() : 'ASC' }; |
| 55 | }); |
| 56 | query = query.replace(orderByRegex, ''); |
| 57 | } |
| 58 | |
| 59 | // Process GROUP BY clause and remove it for further processing |
| 60 | const groupByRegex = /\sGROUP BY\s(.+)/i; |
| 61 | const groupByMatch = query.match(groupByRegex); |
no test coverage detected