diff --git a/.github/.keep b/.github/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/.github/workflows/classroom.yml b/.github/workflows/classroom.yml index dca83b024..8c4fa1b7e 100644 --- a/.github/workflows/classroom.yml +++ b/.github/workflows/classroom.yml @@ -1,19 +1,220 @@ -name: GitHub Classroom Workflow - -on: - - push - - workflow_dispatch - +name: Autograding Tests +'on': +- push +- workflow_dispatch +- repository_dispatch permissions: checks: write actions: read contents: read - jobs: - build: - name: Autograding + run-autograding-tests: runs-on: ubuntu-latest if: github.actor != 'github-classroom[bot]' steps: - - uses: actions/checkout@v4 - - uses: education/autograding@v1 + - name: Checkout code + uses: actions/checkout@v4 + - name: Step-1 Test + id: step-1-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-1 Test + setup-command: npm install + command: npm run test:1 + timeout: 10 + max-score: 10 + - name: Step-2 Test + id: step-2-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-2 Test + setup-command: npm install + command: npm run test:2 + timeout: 10 + max-score: 10 + - name: Step-3 Test + id: step-3-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-3 Test + setup-command: npm install + command: npm run test:3 + timeout: 10 + max-score: 10 + - name: Step-4 Test + id: step-4-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-4 Test + setup-command: npm install + command: npm run test:4 + timeout: 10 + - name: Step-5 Test + id: step-5-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-5 Test + setup-command: npm install + command: npm run test:5 + timeout: 10 + max-score: 10 + - name: Step-6 Test + id: step-6-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-6 Test + setup-command: npm install + command: npm run test:6 + timeout: 10 + max-score: 10 + - name: Step-7 Test + id: step-7-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-7 Test + setup-command: npm install + command: npm run test:7 + timeout: 10 + max-score: 10 + - name: Step-8 Test + id: step-8-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-8 Test + setup-command: npm install + command: npm run test:8 + timeout: 10 + max-score: 10 + - name: Step-9 Test + id: step-9-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-9 Test + setup-command: npm install + command: npm run test:9 + timeout: 10 + max-score: 10 + - name: Step-10 Test + id: step-10-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-10 Test + setup-command: npm install + command: npm run test:10 + timeout: 10 + max-score: 10 + - name: Step-11 Test + id: step-11-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-11 Test + setup-command: npm install + command: npm run test:11 + timeout: 10 + max-score: 10 + - name: Step-12 Test + id: step-12-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-12 Test + setup-command: npm install + command: npm run test:12 + timeout: 10 + max-score: 10 + - name: Step-13 Test + id: step-13-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-13 Test + setup-command: npm install + command: npm run test:13 + timeout: 10 + max-score: 10 + - name: Step-14 Test + id: step-14-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-14 Test + setup-command: npm install + command: npm run test:14 + timeout: 10 + max-score: 10 + - name: Step-15 Test + id: step-15-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-15 Test + setup-command: npm install + command: npm run test:15 + timeout: 10 + max-score: 10 + - name: Step-16 Test + id: step-16-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-16 Test + setup-command: npm install + command: npm run test:16 + timeout: 10 + max-score: 10 + - name: Step-17 Test + id: step-17-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-17 Test + setup-command: npm install + command: npm run test:17 + timeout: 10 + max-score: 10 + - name: Step-18 Test + id: step-18-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-18 Test + setup-command: npm install + command: npm run test:18 + timeout: 10 + max-score: 10 + - name: Step-19 Test + id: step-19-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-19 Test + setup-command: npm install + command: npm run test:19 + timeout: 10 + max-score: 10 + - name: Step-20 Test + id: step-20-test + uses: education/autograding-command-grader@v1 + with: + test-name: Step-20 Test + setup-command: npm install + command: npm run test:20 + timeout: 10 + max-score: 10 + - name: Autograding Reporter + uses: education/autograding-grading-reporter@v1 + env: + STEP-1-TEST_RESULTS: "${{steps.step-1-test.outputs.result}}" + STEP-2-TEST_RESULTS: "${{steps.step-2-test.outputs.result}}" + STEP-3-TEST_RESULTS: "${{steps.step-3-test.outputs.result}}" + STEP-4-TEST_RESULTS: "${{steps.step-4-test.outputs.result}}" + STEP-5-TEST_RESULTS: "${{steps.step-5-test.outputs.result}}" + STEP-6-TEST_RESULTS: "${{steps.step-6-test.outputs.result}}" + STEP-7-TEST_RESULTS: "${{steps.step-7-test.outputs.result}}" + STEP-8-TEST_RESULTS: "${{steps.step-8-test.outputs.result}}" + STEP-9-TEST_RESULTS: "${{steps.step-9-test.outputs.result}}" + STEP-10-TEST_RESULTS: "${{steps.step-10-test.outputs.result}}" + STEP-11-TEST_RESULTS: "${{steps.step-11-test.outputs.result}}" + STEP-12-TEST_RESULTS: "${{steps.step-12-test.outputs.result}}" + STEP-13-TEST_RESULTS: "${{steps.step-13-test.outputs.result}}" + STEP-14-TEST_RESULTS: "${{steps.step-14-test.outputs.result}}" + STEP-15-TEST_RESULTS: "${{steps.step-15-test.outputs.result}}" + STEP-16-TEST_RESULTS: "${{steps.step-16-test.outputs.result}}" + STEP-17-TEST_RESULTS: "${{steps.step-17-test.outputs.result}}" + STEP-18-TEST_RESULTS: "${{steps.step-18-test.outputs.result}}" + STEP-19-TEST_RESULTS: "${{steps.step-19-test.outputs.result}}" + STEP-20-TEST_RESULTS: "${{steps.step-20-test.outputs.result}}" + with: + runners: step-1-test,step-2-test,step-3-test,step-4-test,step-5-test,step-6-test,step-7-test,step-8-test,step-9-test,step-10-test,step-11-test,step-12-test,step-13-test,step-14-test,step-15-test,step-16-test,step-17-test,step-18-test,step-19-test,step-20-test diff --git a/enrollment.csv b/enrollment.csv new file mode 100644 index 000000000..e80af8d93 --- /dev/null +++ b/enrollment.csv @@ -0,0 +1,6 @@ +student_id,course +1,Mathematics +1,Physics +2,Chemistry +3,Mathematics +5,Biology \ No newline at end of file diff --git a/sample.csv b/sample.csv new file mode 100644 index 000000000..9e7a9fa25 --- /dev/null +++ b/sample.csv @@ -0,0 +1,4 @@ +id,name,age +1,John,30 +2,Jane,25 +3,Bob,22 \ No newline at end of file diff --git a/src/cli.js b/src/cli.js new file mode 100644 index 000000000..61a5d7b91 --- /dev/null +++ b/src/cli.js @@ -0,0 +1,73 @@ +#!/usr/bin/env node + +const readline = require("readline"); +const { + executeSELECTQuery, + executeINSERTQuery, + executeDELETEQuery, +} = require("./queryExecutor.js"); + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, +}); + +rl.setPrompt("SQL> "); +console.log( + 'SQL Query Engine CLI. Enter your SQL commands, or type "exit" to quit.' +); + +rl.prompt(); + +rl.on("line", async (line) => { + if (line.toLowerCase() === "exit") { + rl.close(); + return; + } + + try { + // Execute the query - do your own implementation + const query = line.trim(); + + // Determine the type of SQL command (SELECT, INSERT, DELETE, etc.) + const queryType = determineQueryType(query); + + // Execute the appropriate query based on the command type + switch (queryType) { + case "SELECT": + const result = await executeSELECTQuery(query); + console.log("Result:", result); + break; + case "INSERT": + await executeINSERTQuery(query); + console.log("Successfully Inserted"); + break; + case "DELETE": + const msg = await executeDELETEQuery(query); + console.log(msg.message); + break; + default: + throw new Error(`Unsupported SQL command: ${query}`); + } + } catch (error) { + console.error("Error:", error.message); + } + + rl.prompt(); +}).on("close", () => { + console.log("Exiting SQL CLI"); + process.exit(0); +}); + +function determineQueryType(query) { + const normalizedQuery = query.trim().toLowerCase(); + if (normalizedQuery.startsWith("select")) { + return "SELECT"; + } else if (normalizedQuery.startsWith("insert")) { + return "INSERT"; + } else if (normalizedQuery.startsWith("delete")) { + return "DELETE"; + } else { + throw new Error(`Unsupported SQL command: ${query}`); + } +} diff --git a/src/csvReader.js b/src/csvReader.js index e69de29bb..00d7f99e5 100644 --- a/src/csvReader.js +++ b/src/csvReader.js @@ -0,0 +1,78 @@ +// src/csvReader.js + +const fs = require("fs"); +const csv = require("csv-parser"); + +function readCSV(filePath) { + const results = []; + + return new Promise((resolve, reject) => { + fs.createReadStream(filePath) + .pipe(csv()) + .on("data", (data) => results.push(data)) + .on("end", () => { + resolve(results); + }) + .on("error", (error) => { + reject(error); + }); + }); +} + +async function writeCSV(filename, data) { + if (data.length < 1) { + throw new Error("No data to write to CSV"); + } + + // Prepare headers for CSV file + const fields = Object.keys(data[0]); + // let orderedFields = fields; + // let existingData = []; + + // if (fs.existsSync(filename)) { + // // Read existing data from CSV file + // existingData = await readCSV(filename); + // orderedFields = + // existingData.length >= 1 ? Object.keys(existingData[0]) : fields; + // console.log(existingData); + //} + const outputStream = fs.createWriteStream(filename); + + const headers = fields.join(",") + "\n"; + outputStream.write(headers); + + // Prepare new rows to write to CSV file + const newDataRows = data.map((row) => { + return fields.map((field) => row[field]).join(","); + }); + + // Combine existing data with new data + // const allRows = existingData + // .map((row) => { + // return orderedFields.map((field) => row[field]).join(","); + // }) + // .concat(newDataRows); + + // Write all rows to CSV file + newDataRows.forEach((rowData) => { + outputStream.write(rowData + "\n"); + }); + + outputStream.end(); + + return new Promise((resolve, reject) => { + outputStream.on("finish", () => { + resolve(); + }); + + outputStream.on("error", (err) => { + console.error( + `Error occurred while writing CSV file "${filename}":`, + err + ); + reject(err); + }); + }); +} + +module.exports = { readCSV, writeCSV }; diff --git a/src/index.js b/src/index.js new file mode 100644 index 000000000..af5da6da0 --- /dev/null +++ b/src/index.js @@ -0,0 +1,46 @@ +const parseQuery = require("./queryParser"); +const readCSV = require("./csvReader"); + +async function executeSELECTQuery(query) { + const { fields, table, whereClauses } = parseQuery(query); + const data = await readCSV(`${table}.csv`); + + // Apply WHERE clause filtering + const filteredData = + whereClauses.length > 0 + ? data.filter((row) => + whereClauses.every((clause) => evaluateCondition(row, clause)) + ) + : data; + + // Select the specified fields + return filteredData.map((row) => { + const selectedRow = {}; + fields.forEach((field) => { + selectedRow[field] = row[field]; + }); + return selectedRow; + }); +} + +function evaluateCondition(row, clause) { + const { field, operator, value } = clause; + switch (operator) { + case "=": + return row[field] === value; + case "!=": + return row[field] !== value; + case ">": + return row[field] > value; + case "<": + return row[field] < value; + case ">=": + return row[field] >= value; + case "<=": + return row[field] <= value; + default: + throw new Error(`Unsupported operator: ${operator}`); + } +} + +module.exports = executeSELECTQuery; diff --git a/src/queryExecutor.js b/src/queryExecutor.js new file mode 100644 index 000000000..e6f42f637 --- /dev/null +++ b/src/queryExecutor.js @@ -0,0 +1,369 @@ +// src/index.js +const fs = require("fs"); +const { + parseSelectQuery, + removeQuotes, + parseINSERTQuery, + parseDeleteQuery, +} = require("./queryParser"); +const { readCSV, writeCSV } = require("./csvReader"); + +function evaluateCondition(row, clause) { + const { field, operator, value } = clause; + const newValue = removeQuotes(value); + switch (operator) { + case "=": + return row[field] === newValue; + case "!=": + return row[field] !== newValue; + case ">": + return row[field] > newValue; + case "<": + return row[field] < newValue; + case ">=": + return row[field] >= newValue; + case "<=": + return row[field] <= newValue; + case "LIKE": + const regexPattern = "^" + clause.value.replace(/%/g, ".*") + "$"; + return new RegExp(regexPattern, "i").test(row[clause.field]); + default: + throw new Error(`Unsupported operator: ${operator}`); + } +} + +function aggregatedOperations(aggregateFunction, rows) { + const [op, fieldName] = aggregateFunction + .split("(") + .map((part) => part.trim().replace(")", "")); + if (fieldName === "*") { + return rows.length; + } + + const values = rows.map((row) => row[fieldName]); + + let result; + switch (op.toUpperCase()) { + case "COUNT": + result = values.length; + break; + case "AVG": + result = + values.reduce((acc, val) => acc + Number(val), 0) / values.length; + break; + case "MAX": + result = Math.max(...values); + break; + case "MIN": + result = Math.min(...values); + break; + case "SUM": + result = values.reduce((acc, val) => acc + Number(val), 0); + break; + // Handle other aggregate functions if needed + default: + throw new Error(`Unsupported aggregate function: ${op}`); + } + + return result; +} + +// Helper function to apply GROUP BY and aggregate functions +function applyGroupBy(data, groupByFields, aggregateFunctions) { + const groupedData = data.reduce((acc, row) => { + //generate a group key from group by fields for each distinct possible group + const groupKey = groupByFields.map((field) => row[field]).join("_"); + + if (!acc[groupKey]) { + acc[groupKey] = []; + } + //group the rows according to the groupKey + acc[groupKey].push(row); + + return acc; + }, {}); + + const aggregatedData = Object.entries(groupedData).map( + ([groupKey, groupRows]) => { + const group = {}; + + const groupRowValues = groupKey.split("_"); + groupByFields.forEach((field, index) => { + group[field] = groupRowValues[index]; + aggregateFunctions = aggregateFunctions.filter((func) => { + return func !== field; + }); + }); + + aggregateFunctions.forEach((func) => { + group[`${func}`] = aggregatedOperations(func, groupRows); + }); + + return group; + } + ); + + return aggregatedData; +} + +// Helper functions for different JOIN types +function performInnerJoin(data, joinData, joinCondition, fields, table) { + data = data.flatMap((mainRow) => { + return joinData + .filter((joinRow) => { + const mainValue = mainRow[joinCondition.left.split(".")[1]]; + const joinValue = joinRow[joinCondition.right.split(".")[1]]; + return mainValue === joinValue; + }) + .map((joinRow) => { + return fields.reduce((acc, field) => { + const [tableName, fieldName] = field.split("."); + acc[field] = + tableName === table ? mainRow[fieldName] : joinRow[fieldName]; + return acc; + }, {}); + }); + }); + + return data; +} + +function performLeftJoin(data, joinData, joinCondition, fields, table) { + data = data.flatMap((mainRow) => { + const matchingRows = joinData.filter((joinRow) => { + const mainValue = mainRow[joinCondition.left.split(".")[1]]; + const joinValue = joinRow[joinCondition.right.split(".")[1]]; + return mainValue === joinValue; + }); + + //no matching row found for particular main row + if (matchingRows.length == 0) { + return fields.reduce((acc, field) => { + const [tablename, fieldname] = field.split("."); + acc[field] = tablename === table ? mainRow[fieldname] : null; + return acc; + }, {}); + } + + //matching rows exist + return matchingRows.map((joinRow) => { + return fields.reduce((acc, field) => { + const [tableName, fieldName] = field.split("."); + acc[field] = + tableName === table ? mainRow[fieldName] : joinRow[fieldName]; + return acc; + }, {}); + }); + }); + + return data; +} + +function performRightJoin(data, joinData, joinCondition, fields, table) { + joinData = joinData.flatMap((joinRow) => { + const matchingRows = data.filter((mainRow) => { + const mainValue = mainRow[joinCondition.left.split(".")[1]]; + const joinValue = joinRow[joinCondition.right.split(".")[1]]; + return mainValue === joinValue; + }); + + //matching values dont exist for particular join row + if (matchingRows.length == 0) { + return fields.reduce((acc, field) => { + const [tablename, fieldname] = field.split("."); + acc[field] = tablename === table ? null : joinRow[fieldname]; + return acc; + }, {}); + } + + //matching rows exist + return matchingRows.map((mainRow) => { + return fields.reduce((acc, field) => { + const [tablename, fieldname] = field.split("."); + acc[field] = + tablename === table ? mainRow[fieldname] : joinRow[fieldname]; + return acc; + }, {}); + }); + }); + + return joinData; +} + +async function executeSELECTQuery(query) { + try { + const { + fields, + table, + whereClauses, + joinType, + joinTable, + joinCondition, + groupByFields, + hasAggregateWithoutGroupBy, + orderByFields, + limit, + isDistinct, + } = parseSelectQuery(query); + let data = await readCSV(`${table}.csv`); + + // Logic for applying JOINs + if (joinTable && joinCondition) { + const joinData = await readCSV(`${joinTable}.csv`); + + const dataKeys = data + ? Object.keys(data[0]).map((key) => `${table}.${key}`) + : []; + const joinDataKeys = joinData + ? Object.keys(joinData[0]).map((key) => `${joinTable}.${key}`) + : []; + const allFields = [...dataKeys, ...joinDataKeys]; + + switch (joinType.toUpperCase()) { + case "INNER": + data = performInnerJoin( + data, + joinData, + joinCondition, + allFields, + table + ); + break; + case "LEFT": + data = performLeftJoin( + data, + joinData, + joinCondition, + allFields, + table + ); + break; + case "RIGHT": + data = performRightJoin( + data, + joinData, + joinCondition, + allFields, + table + ); + break; + // Handle default case or unsupported JOIN types + default: + throw new Error(`Unsupported JOIN type: ${joinType.ToUpperCase()}`); + } + } + + // logic for WHERE clause + let filteredData = + whereClauses.length > 0 + ? data.filter((row) => + whereClauses.every((clause) => evaluateCondition(row, clause)) + ) + : data; + + // logic for group by + if (groupByFields) { + filteredData = applyGroupBy(filteredData, groupByFields, fields); + } + + if (hasAggregateWithoutGroupBy && fields.length == 1) { + const selectedRow = {}; + selectedRow[fields[0]] = aggregatedOperations(fields[0], filteredData); + return [selectedRow]; + } + + // console.log("AFTER GROUP: ", filteredData); + + if (orderByFields) { + filteredData.sort((a, b) => { + for (let { fieldName, order } of orderByFields) { + if (a[fieldName] < b[fieldName]) return order === "ASC" ? -1 : 1; + if (a[fieldName] > b[fieldName]) return order === "ASC" ? 1 : -1; + } + return 0; + }); + } + + // console.log("AFTER ORDER: ", filteredData); + + if (limit !== null) { + filteredData = filteredData.slice(0, limit); + } + + if (isDistinct) { + filteredData = [ + ...new Map( + filteredData.map((item) => [ + fields.map((field) => item[field]).join("|"), + item, + ]) + ).values(), + ]; + } + + // Filter the fields based on the query fields + return filteredData.map((row) => { + const selectedRow = {}; + fields.forEach((field) => { + if (hasAggregateWithoutGroupBy) { + selectedRow[field] = aggregatedOperations(field, filteredData); + } else { + selectedRow[field] = row[field]; + } + }); + return selectedRow; + }); + } catch (error) { + throw new Error(`Error executing query: ${error.message}`); + } +} + +async function executeINSERTQuery(query) { + const { type, table, columns, values } = parseINSERTQuery(query); + + if (type !== "INSERT") { + throw new Error("Invalid INSERT format"); + } + + let orderedFields = columns; + let existingData = []; + + if (fs.existsSync(`${table}.csv`)) { + // Read existing data from CSV file + existingData = await readCSV(`${table}.csv`); + orderedFields = + existingData.length >= 1 ? Object.keys(existingData[0]) : columns; + } + + const data = [ + orderedFields.reduce((acc, field, index) => { + acc[field] = values[index]; + return acc; + }, {}), + ]; + + const newData = existingData.concat(data); + + await writeCSV(`${table}.csv`, newData); +} +// src/queryExecutor.js + +async function executeDELETEQuery(query) { + const { table, whereClauses } = parseDeleteQuery(query); + + let data = await readCSV(`${table}.csv`); + + const filteredData = + whereClauses.length > 0 + ? data.filter((row) => + whereClauses.every((clause) => !evaluateCondition(row, clause)) + ) + : []; + + // Save the updated data back to the CSV file + await writeCSV(`${table}.csv`, filteredData); + + return { message: "Rows deleted successfully." }; +} + +module.exports = { executeSELECTQuery, executeINSERTQuery, executeDELETEQuery }; diff --git a/src/queryParser.js b/src/queryParser.js new file mode 100644 index 000000000..4fed4638d --- /dev/null +++ b/src/queryParser.js @@ -0,0 +1,229 @@ +function parseDeleteQuery(query) { + query = query.trim(); + + // Where Clause logic + const whereSplit = query.split(/\sWHERE\s/i); + query = whereSplit[0]; // Everything before WHERE clause + const whereClause = whereSplit.length > 1 ? whereSplit[1].trim() : null; + let whereClauses = []; + if (whereClause) { + whereClauses = parseWhereClause(whereClause); + } + + //insert regex + const deleteRegex = /^DELETE FROM\s+(\w+)/i; + const deleteMatch = query.match(deleteRegex); + + if (!deleteMatch) { + throw new Error("Invalid DELETE format"); + } + + const [, table] = deleteMatch; + + return { + type: "DELETE", + table: table.trim(), + whereClauses: whereClauses, + }; +} + +function parseINSERTQuery(query) { + query = query.trim(); + + //insert regex + const insertPattern = + /^INSERT INTO\s+(\w+)\s+\(([^)]+)\)\s+VALUES\s+\(([^)]+)\)/i; + + const insertMatch = query.match(insertPattern); + + if (!insertMatch) { + throw new Error("Invalid INSERT format"); + } + + const [, table, fields, values] = insertMatch; + return { + type: "INSERT", + table: table.trim(), + columns: fields.split(",").map((field) => removeQuotes(field.trim())), + values: values.split(",").map((val) => removeQuotes(val.trim())), + }; +} + +function parseSelectQuery(query) { + try { + // First, let's trim the query to remove any leading/trailing whitespaces + query = query.trim(); + + let isDistinct = false; + if (query.toUpperCase().includes("SELECT DISTINCT")) { + isDistinct = true; + query = query.replace("SELECT DISTINCT", "SELECT"); + } + + // Updated regex to capture LIMIT clause + const limitRegex = /\sLIMIT\s(\d+)/i; + const limitMatch = query.match(limitRegex); + + let limit = null; + if (limitMatch) { + query = query.split(/\sLIMIT\s/i)[0]; + limit = parseInt(limitMatch[1]); + } + + // Updated regex to capture ORDER BY clause + const orderByRegex = /\sORDER BY\s(.+)/i; + const orderByMatch = query.match(orderByRegex); + + let orderByFields = null; + if (orderByMatch) { + query = query.split(/\sORDER BY\s/i)[0]; + orderByFields = orderByMatch[1].split(",").map((field) => { + const [fieldName, order] = field.trim().split(/\s+/); + return { fieldName, order: order ? order.toUpperCase() : "ASC" }; + }); + } + + // Updated regex to capture GROUP BY clause + const groupByRegex = /\sGROUP BY\s(.+)/i; + const groupByMatch = query.match(groupByRegex); + + let groupByFields = null; + + if (groupByMatch) { + groupByFields = groupByMatch[1].split(",").map((field) => field.trim()); + query = query.split(/\sGROUP BY\s/i)[0]; + } + + const aggRegex = /\s(COUNT|AVG|MAX|MIN|SUM)\(.*?\)/gi; + const aggMatch = query.match(aggRegex); + + let hasAggregateWithoutGroupBy = false; + if (!groupByMatch && aggMatch) { + hasAggregateWithoutGroupBy = true; + } + + // Initialize variables for different parts of the query + let selectPart, fromPart; + + // Split the query at the WHERE clause if it exists + const whereSplit = query.split(/\sWHERE\s/i); + query = whereSplit[0]; // Everything before WHERE clause + + // WHERE clause is the second part after splitting, if it exists + const whereClause = whereSplit.length > 1 ? whereSplit[1].trim() : null; + + // Split the remaining query at the JOIN clause if it exists + const joinSplit = query.split(/\s(INNER|LEFT|RIGHT) JOIN\s/i); + selectPart = joinSplit[0].trim(); // Everything before JOIN clause + + // Parse the SELECT part + const selectRegex = /^SELECT\s(.+?)\sFROM\s(.+)/i; + const selectMatch = selectPart.match(selectRegex); + if (!selectMatch) { + throw new Error("Invalid SELECT format"); + } + + const [, fields, table] = selectMatch; + + // Parse the JOIN part if it exists + const { joinType, joinTable, joinCondition } = parseJoinClause(query); + + // Parse the WHERE part if it exists + let whereClauses = []; + if (whereClause) { + whereClauses = parseWhereClause(whereClause); + } + + return { + fields: fields.split(",").map((field) => field.trim()), + table: table.trim(), + whereClauses, + joinType, + joinTable, + joinCondition, + groupByFields, + hasAggregateWithoutGroupBy, + orderByFields, + limit, + isDistinct, + }; + } catch (error) { + // console.error(error); + throw new Error(`Query parsing error: ${error.message}`); + } +} + +function parseWhereClause(whereString) { + try { + const conditionRegex = /(.*?)(=|!=|>|<|>=|<=)(.*)/; + return whereString.split(/ AND | OR /i).map((conditionString) => { + const match = conditionString.match(conditionRegex); + + if (conditionString.includes(" LIKE ")) { + const [field, pattern] = conditionString.split(/\sLIKE\s/i); + return { + field: field.trim(), + operator: "LIKE", + value: removeQuotes(pattern.trim()), + }; + } + + if (match) { + const [, field, operator, value] = match; + + // to remove cases of 'value' + + return { + field: field.trim(), + operator, + value: value.trim(), + }; + } + throw new Error("Invalid WHERE clause format"); + }); + } catch (error) { + throw error; + } +} + +function parseJoinClause(query) { + const joinRegex = + /\s(INNER|LEFT|RIGHT) JOIN\s(.+?)\sON\s([\w.]+)\s*=\s*([\w.]+)/i; + const joinMatch = query.match(joinRegex); + + if (joinMatch) { + return { + joinType: joinMatch[1].trim(), + joinTable: joinMatch[2].trim(), + joinCondition: { + left: joinMatch[3].trim(), + right: joinMatch[4].trim(), + }, + }; + } + + return { + joinType: null, + joinTable: null, + joinCondition: null, + }; +} + +function removeQuotes(value) { + if ( + typeof value === "string" && + (value.startsWith(`'`) || value.startsWith(`"`)) && + (value.endsWith(`'`) || value.endsWith(`"`)) + ) { + return value.slice(1, -1); // Remove quotes + } + return value; +} + +module.exports = { + parseSelectQuery, + parseJoinClause, + removeQuotes, + parseINSERTQuery, + parseDeleteQuery, +}; diff --git a/student.csv b/student.csv new file mode 100644 index 000000000..e9c960121 --- /dev/null +++ b/student.csv @@ -0,0 +1,5 @@ +id,name,age +1,John,30 +2,Jane,25 +3,Bob,22 +4,Alice,24 \ No newline at end of file diff --git a/tests/cli.test.js b/tests/cli.test.js new file mode 100644 index 000000000..1a3eab324 --- /dev/null +++ b/tests/cli.test.js @@ -0,0 +1,53 @@ +const child_process = require("child_process"); +const path = require("path"); + +test("DISTINCT with Multiple Columns via CLI", (done) => { + const cliPath = path.join(__dirname, "..", "src", "cli.js"); + const cliProcess = child_process.spawn("node", [cliPath]); + + let outputData = ""; + cliProcess.stdout.on("data", (data) => { + outputData += data.toString(); + }); + + cliProcess.on("exit", () => { + // Define a regex pattern to extract the JSON result + + const cleanedOutput = outputData.replace(/\s+/g, " "); + + const resultRegex = /Result: (\[.+\])/s; + const match = cleanedOutput.match(resultRegex); + + // Fix JSON outputput + match[1] = match[1].replace(/'/g, '"').replace(/(\w+):/g, '"$1":'); + + if (match && match[1]) { + // Parse the captured JSON string + + const results = JSON.parse(match[1].trim()); + + // Validation logic + expect(results).toEqual([ + { student_id: "1", course: "Mathematics" }, + { student_id: "1", course: "Physics" }, + { student_id: "2", course: "Chemistry" }, + { student_id: "3", course: "Mathematics" }, + { student_id: "5", course: "Biology" }, + ]); + } else { + throw new Error("Failed to parse CLI output"); + } + + done(); + }); + + // Introduce a delay before sending the query + setTimeout(() => { + cliProcess.stdin.write( + "SELECT DISTINCT student_id, course FROM enrollment\n" + ); + setTimeout(() => { + cliProcess.stdin.write("exit\n"); + }, 1000); // 1 second delay + }, 1000); // 1 second delay +}); diff --git a/tests/csvReader.test.js b/tests/csvReader.test.js new file mode 100644 index 000000000..97e38ee34 --- /dev/null +++ b/tests/csvReader.test.js @@ -0,0 +1,10 @@ +const { readCSV, writeCSV } = require("../src/csvReader"); +const fs = require("fs"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); diff --git a/tests/deleteExecutor.test.js b/tests/deleteExecutor.test.js new file mode 100644 index 000000000..09d1b7f31 --- /dev/null +++ b/tests/deleteExecutor.test.js @@ -0,0 +1,31 @@ +const { executeDELETEQuery } = require("../src/queryExecutor"); +const { readCSV, writeCSV } = require("../src/csvReader"); +const fs = require("fs"); + +// Helper function to create courses.csv with initial data +async function createCoursesCSV() { + const initialData = [ + { course_id: "1", course_name: "Mathematics", instructor: "Dr. Smith" }, + { course_id: "2", course_name: "Chemistry", instructor: "Dr. Jones" }, + { course_id: "3", course_name: "Physics", instructor: "Dr. Taylor" }, + ]; + await writeCSV("courses.csv", initialData); +} + +// Test to DELETE a course and verify +test("Execute DELETE FROM Query for courses.csv", async () => { + // Create courses.csv with initial data + await createCoursesCSV(); + + // Execute DELETE statement + const deleteQuery = "DELETE FROM courses WHERE course_id = '2'"; + await executeDELETEQuery(deleteQuery); + + // Verify the course was removed + const updatedData = await readCSV("courses.csv"); + const deletedCourse = updatedData.find((course) => course.course_id === "2"); + expect(deletedCourse).toBeUndefined(); + + // Cleanup: Delete courses.csv + fs.unlinkSync("courses.csv"); +}); diff --git a/tests/insertExecutor.test.js b/tests/insertExecutor.test.js new file mode 100644 index 000000000..05589043e --- /dev/null +++ b/tests/insertExecutor.test.js @@ -0,0 +1,36 @@ +const { executeINSERTQuery } = require("../src/queryExecutor"); +const { readCSV, writeCSV } = require("../src/csvReader"); +const fs = require("fs"); + +// Helper function to create grades.csv with initial data +async function createGradesCSV() { + const initialData = [ + { student_id: "1", course: "Mathematics", grade: "A" }, + { student_id: "2", course: "Chemistry", grade: "B" }, + { student_id: "3", course: "Mathematics", grade: "C" }, + ]; + await writeCSV("grades.csv", initialData); +} + +// Test to INSERT a new grade and verify +test("Execute INSERT INTO Query for grades.csv", async () => { + // Create grades.csv with initial data + await createGradesCSV(); + + // Execute INSERT statement + const insertQuery = + "INSERT INTO grades (student_id, course, grade) VALUES ('4', 'Physics', 'A')"; + await executeINSERTQuery(insertQuery); + + // Verify the new entry + const updatedData = await readCSV("grades.csv"); + const newEntry = updatedData.find( + (row) => row.student_id === "4" && row.course === "Physics" + ); + + expect(newEntry).toBeDefined(); + expect(newEntry.grade).toEqual("A"); + + // Cleanup: Delete grades.csv + fs.unlinkSync("grades.csv"); +}); diff --git a/tests/queryExecutor.test.js b/tests/queryExecutor.test.js new file mode 100644 index 000000000..72df2f9b8 --- /dev/null +++ b/tests/queryExecutor.test.js @@ -0,0 +1,446 @@ +const { executeSELECTQuery } = require("../src/queryExecutor"); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); +}); + +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* + result = [ + { + 'student.name': 'John', + 'enrollment.course': 'Mathematics', + 'student.age': '30' + }, + { + 'student.name': 'John', + 'enrollment.course': 'Physics', + 'student.age': '30' + } + ] + */ + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "enrollment.course": "Physics", + "student.name": "John", + }), + ]) + ); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Physics", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); + +test("Execute COUNT Aggregate Query", async () => { + const query = "SELECT COUNT(*) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "COUNT(*)": 4 }]); +}); + +test("Execute SUM Aggregate Query", async () => { + const query = "SELECT SUM(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "SUM(age)": 101 }]); +}); + +test("Execute AVG Aggregate Query", async () => { + const query = "SELECT AVG(age) FROM student"; + const result = await executeSELECTQuery(query); + // Assuming AVG returns a single decimal point value + expect(result).toEqual([{ "AVG(age)": 25.25 }]); +}); + +test("Execute MIN Aggregate Query", async () => { + const query = "SELECT MIN(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MIN(age)": 22 }]); +}); + +test("Execute MAX Aggregate Query", async () => { + const query = "SELECT MAX(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MAX(age)": 30 }]); +}); + +test("Count students per age", async () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "22", "COUNT(*)": 1 }, + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments per course", async () => { + const query = "SELECT course, COUNT(*) FROM enrollment GROUP BY course"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { course: "Mathematics", "COUNT(*)": 2 }, + { course: "Physics", "COUNT(*)": 1 }, + { course: "Chemistry", "COUNT(*)": 1 }, + { course: "Biology", "COUNT(*)": 1 }, + ]); +}); + +test("Count courses per student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { student_id: "1", "COUNT(*)": 2 }, + { student_id: "2", "COUNT(*)": 1 }, + { student_id: "3", "COUNT(*)": 1 }, + { student_id: "5", "COUNT(*)": 1 }, + ]); +}); + +test("Count students within a specific age range", async () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments for a specific course", async () => { + const query = + 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ course: "Mathematics", "COUNT(*)": 2 }]); +}); + +test("Count courses for a specific student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ student_id: "1", "COUNT(*)": 2 }]); +}); + +test("Average age of students above a certain age", async () => { + const query = "SELECT AVG(age) FROM student WHERE age > 22"; + const result = await executeSELECTQuery(query); + const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 + expect(result).toEqual([{ "AVG(age)": expectedAverage }]); +}); + +test("Execute SQL Query with ORDER BY", async () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { name: "Alice" }, + { name: "Bob" }, + { name: "Jane" }, + { name: "John" }, + ]); +}); + +test("Execute SQL Query with ORDER BY and WHERE", async () => { + const query = "SELECT name FROM student WHERE age > 24 ORDER BY name DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([{ name: "John" }, { name: "Jane" }]); +}); +test("Execute SQL Query with ORDER BY and GROUP BY", async () => { + const query = + "SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { age: "30", "COUNT(id) as count": 1 }, + { age: "25", "COUNT(id) as count": 1 }, + { age: "24", "COUNT(id) as count": 1 }, + { age: "22", "COUNT(id) as count": 1 }, + ]); +}); + +test("Execute SQL Query with standard LIMIT clause", async () => { + const query = "SELECT id, name FROM student LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with LIMIT clause equal to total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 4"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LIMIT clause exceeding total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 10"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); // Total rows in student.csv +}); + +test("Execute SQL Query with LIMIT 0", async () => { + const query = "SELECT id, name FROM student LIMIT 0"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(0); +}); + +test("Execute SQL Query with LIMIT and ORDER BY clause", async () => { + const query = "SELECT id, name FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); + expect(result[0].name).toEqual("John"); + expect(result[1].name).toEqual("Jane"); +}); + +test("Error Handling with Malformed Query", async () => { + const query = "SELECT FROM table"; // intentionally malformed + await expect(executeSELECTQuery(query)).rejects.toThrow( + "Error executing query: Query parsing error: Invalid SELECT format" + ); +}); + +test("Basic DISTINCT Usage", async () => { + const query = "SELECT DISTINCT age FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "30" }, + { age: "25" }, + { age: "22" }, + { age: "24" }, + ]); +}); + +test("DISTINCT with Multiple Columns", async () => { + const query = "SELECT DISTINCT student_id, course FROM enrollment"; + const result = await executeSELECTQuery(query); + // Expecting unique combinations of student_id and course + expect(result).toEqual([ + { student_id: "1", course: "Mathematics" }, + { student_id: "1", course: "Physics" }, + { student_id: "2", course: "Chemistry" }, + { student_id: "3", course: "Mathematics" }, + { student_id: "5", course: "Biology" }, + ]); +}); + +// Not a good test right now +test("DISTINCT with WHERE Clause", async () => { + const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; + const result = await executeSELECTQuery(query); + // Expecting courses taken by student with ID 1 + expect(result).toEqual([{ course: "Mathematics" }, { course: "Physics" }]); +}); + +test("DISTINCT with JOIN Operations", async () => { + const query = + "SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id"; + const result = await executeSELECTQuery(query); + // Expecting names of students who are enrolled in any course + expect(result).toEqual([ + { "student.name": "John" }, + { "student.name": "Jane" }, + { "student.name": "Bob" }, + ]); +}); + +test("DISTINCT with ORDER BY and LIMIT", async () => { + const query = "SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the two highest unique ages + expect(result).toEqual([{ age: "30" }, { age: "25" }]); +}); + +test("Execute SQL Query with LIKE Operator for Name", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; + const result = await executeSELECTQuery(query); + // Expecting names containing 'Jane' + expect(result).toEqual([{ name: "Jane" }]); +}); + +test("Execute SQL Query with LIKE Operator and Wildcards", async () => { + const query = "SELECT name FROM student WHERE name LIKE 'J%'"; + const result = await executeSELECTQuery(query); + // Expecting names starting with 'J' + expect(result).toEqual([{ name: "John" }, { name: "Jane" }]); +}); + +test("Execute SQL Query with LIKE Operator Case Insensitive", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%bob%'"; + const result = await executeSELECTQuery(query); + // Expecting names 'Bob' (case insensitive) + expect(result).toEqual([{ name: "Bob" }]); +}); + +test("Execute SQL Query with LIKE Operator and DISTINCT", async () => { + const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%'"; + const result = await executeSELECTQuery(query); + // Expecting unique names containing 'e' + expect(result).toEqual([{ name: "Jane" }, { name: "Alice" }]); +}); + +test("LIKE with ORDER BY and LIMIT", async () => { + const query = + "SELECT name FROM student WHERE name LIKE '%a%' ORDER BY name ASC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the first two names alphabetically that contain 'a' + expect(result).toEqual([{ name: "Alice" }, { name: "Jane" }]); +}); diff --git a/tests/queryParser.test.js b/tests/queryParser.test.js new file mode 100644 index 000000000..b1d4acf81 --- /dev/null +++ b/tests/queryParser.test.js @@ -0,0 +1,686 @@ +const { parseJoinClause, parseSelectQuery } = require("../src/queryParser"); + +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse INNER JOIN clause", () => { + const query = + "SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "INNER", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse LEFT JOIN clause", () => { + const query = + "SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "LEFT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse RIGHT JOIN clause", () => { + const query = + "SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "RIGHT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Returns null for queries without JOIN", () => { + const query = "SELECT * FROM table1"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: null, + joinTable: null, + joinCondition: null, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "LEFT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "RIGHT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "22" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Physics'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [{ field: "student.age", operator: "<", value: "25" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Chemistry'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse COUNT Aggregate Query", () => { + const query = "SELECT COUNT(*) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SUM Aggregate Query", () => { + const query = "SELECT SUM(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["SUM(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse AVG Aggregate Query", () => { + const query = "SELECT AVG(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["AVG(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MIN Aggregate Query", () => { + const query = "SELECT MIN(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MIN(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MAX Aggregate Query", () => { + const query = "SELECT MAX(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MAX(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse basic GROUP BY query", () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with WHERE clause", () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [{ field: "age", operator: ">", value: "22" }], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with multiple fields", () => { + const query = + "SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course", "COUNT(*)"], + table: "enrollment", + whereClauses: [], + groupByFields: ["student_id", "course"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with JOIN and WHERE clauses", () => { + const query = + 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name", "COUNT(*)"], + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: '"Mathematics"' }, + ], + groupByFields: ["student.name"], + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with ORDER BY", () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const parsed = parseSelectQuery(query); + expect(parsed.orderByFields).toEqual([{ fieldName: "name", order: "ASC" }]); +}); + +test("Parse SQL Query with ORDER BY and WHERE", () => { + const query = "SELECT name FROM student WHERE age > 20 ORDER BY name DESC"; + const parsed = parseSelectQuery(query); + expect(parsed.orderByFields).toEqual([{ fieldName: "name", order: "DESC" }]); + expect(parsed.whereClauses.length).toBeGreaterThan(0); +}); + +test("Parse SQL Query with ORDER BY and GROUP BY", () => { + const query = + "SELECT COUNT(id), age FROM student GROUP BY age ORDER BY age DESC"; + const parsed = parseSelectQuery(query); + expect(parsed.orderByFields).toEqual([{ fieldName: "age", order: "DESC" }]); + expect(parsed.groupByFields).toEqual(["age"]); +}); + +test("Parse SQL Query with standard LIMIT clause", () => { + const query = "SELECT id, name FROM student LIMIT 2"; + const parsed = parseSelectQuery(query); + expect(parsed.limit).toEqual(2); +}); + +test("Parse SQL Query with large number in LIMIT clause", () => { + const query = "SELECT id, name FROM student LIMIT 1000"; + const parsed = parseSelectQuery(query); + expect(parsed.limit).toEqual(1000); +}); + +test("Parse SQL Query without LIMIT clause", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed.limit).toBeNull(); +}); + +test("Parse SQL Query with LIMIT 0", () => { + const query = "SELECT id, name FROM student LIMIT 0"; + const parsed = parseSelectQuery(query); + expect(parsed.limit).toEqual(0); +}); + +test("Parse SQL Query with negative number in LIMIT clause", () => { + const query = "SELECT id, name FROM student LIMIT -1"; + const parsed = parseSelectQuery(query); + // Assuming the parser sets limit to null for invalid values + expect(parsed.limit).toBeNull(); +}); + +test("Error Handling with Malformed Query", async () => { + const query = "SELECT FROM table"; // intentionally malformed + expect(() => parseSelectQuery(query)).toThrow( + "Query parsing error: Invalid SELECT format" + ); +}); + +test("Parse SQL Query with Basic DISTINCT", () => { + const query = "SELECT DISTINCT age FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age"], + table: "student", + isDistinct: true, + whereClauses: [], + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with DISTINCT and Multiple Columns", () => { + const query = "SELECT DISTINCT student_id, course FROM enrollment"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course"], + table: "enrollment", + isDistinct: true, + whereClauses: [], + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with DISTINCT and WHERE Clause", () => { + const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["course"], + table: "enrollment", + isDistinct: true, + whereClauses: [{ field: "student_id", operator: "=", value: '"1"' }], + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with DISTINCT and JOIN Operations", () => { + const query = + "SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name"], + table: "student", + isDistinct: true, + whereClauses: [], + groupByFields: null, + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + orderByFields: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with DISTINCT, ORDER BY, and LIMIT", () => { + const query = "SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age"], + table: "student", + isDistinct: true, + whereClauses: [], + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: [{ fieldName: "age", order: "DESC" }], + limit: 2, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with DISTINCT on All Columns", () => { + const query = "SELECT DISTINCT * FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["*"], + table: "student", + isDistinct: true, + whereClauses: [], + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with LIKE Clause", () => { + const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["name"], + table: "student", + whereClauses: [{ field: "name", operator: "LIKE", value: "%Jane%" }], + isDistinct: false, + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with LIKE Clause and Wildcards", () => { + const query = "SELECT name FROM student WHERE name LIKE 'J%'"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["name"], + table: "student", + whereClauses: [{ field: "name", operator: "LIKE", value: "J%" }], + isDistinct: false, + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with Multiple LIKE Clauses", () => { + const query = + "SELECT name FROM student WHERE name LIKE 'J%' AND age LIKE '2%'"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["name"], + table: "student", + whereClauses: [ + { field: "name", operator: "LIKE", value: "J%" }, + { field: "age", operator: "LIKE", value: "2%" }, + ], + isDistinct: false, + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with LIKE and ORDER BY Clauses", () => { + const query = + "SELECT name FROM student WHERE name LIKE '%e%' ORDER BY age DESC"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["name"], + table: "student", + whereClauses: [{ field: "name", operator: "LIKE", value: "%e%" }], + orderByFields: [{ fieldName: "age", order: "DESC" }], + isDistinct: false, + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); diff --git a/tests/step-02/index.test.js b/tests/step-02/index.test.js index a5467ee48..6ad3d05eb 100644 --- a/tests/step-02/index.test.js +++ b/tests/step-02/index.test.js @@ -1,9 +1,9 @@ -const readCSV = require('../../src/csvReader'); +const { readCSV } = require("../../src/csvReader"); -test('Read CSV File', async () => { - const data = await readCSV('./sample.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(3); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); \ No newline at end of file +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); diff --git a/tests/step-03/index.test.js b/tests/step-03/index.test.js index 9145ad3e4..7aa439f2a 100644 --- a/tests/step-03/index.test.js +++ b/tests/step-03/index.test.js @@ -1,19 +1,34 @@ -const readCSV = require('../../src/csvReader'); -const parseQuery = require('../../src/queryParser'); +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); -test('Read CSV File', async () => { - const data = await readCSV('./sample.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(3); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later }); -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM sample'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'sample' - }); -}); \ No newline at end of file +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); +}); + +test("Invalid SQL Query", () => { + const query = "SELEC id FROM student"; + expect(() => parseSelectQuery(query)).toThrow(); +}); diff --git a/tests/step-04/index.test.js b/tests/step-04/index.test.js index bc353dd3d..c7f6fce83 100644 --- a/tests/step-04/index.test.js +++ b/tests/step-04/index.test.js @@ -1,30 +1,39 @@ -const readCSV = require('../../src/csvReader'); -const parseQuery = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); -test('Read CSV File', async () => { - const data = await readCSV('./sample.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(3); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later }); -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM sample'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'sample' - }); +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + table: "student", + whereClauses: [], + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM sample'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); \ No newline at end of file +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); diff --git a/tests/step-05/index.test.js b/tests/step-05/index.test.js index 66a77c061..54e93b2e9 100644 --- a/tests/step-05/index.test.js +++ b/tests/step-05/index.test.js @@ -1,50 +1,79 @@ -const readCSV = require('../../src/csvReader'); -const parseQuery = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); -test('Read CSV File', async () => { - const data = await readCSV('./sample.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(3); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later }); -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM sample'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'sample', - whereClause: null - }); +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM sample'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); }); -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM sample WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'sample', - whereClause: 'age = 25' - }); +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM sample WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); \ No newline at end of file +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +// check if case sensitive +test("Case Sensitivity Check", async () => { + const query = "SELECT id, name FROM student WHERE name = john"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(0); +}); diff --git a/tests/step-06/index.test.js b/tests/step-06/index.test.js index 2e2ef6416..a264d4cea 100644 --- a/tests/step-06/index.test.js +++ b/tests/step-06/index.test.js @@ -1,79 +1,115 @@ -const readCSV = require('../../src/csvReader'); -const parseQuery = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); -test('Read CSV File', async () => { - const data = await readCSV('./sample.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(3); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later }); -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM sample'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'sample', - whereClauses: [] - }); +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM sample'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); }); -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM sample WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'sample', - whereClauses: [{ - field: "age", - operator: "=", - value: "25", - }], - }); +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM sample WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); }); -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM sample WHERE age = 30 AND name = John'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'sample', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }] - }); +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query with Multiple WHERE Clause', async () => { - const query = 'SELECT id, name FROM sample WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); \ No newline at end of file +test("Execute SQL Query with Multiple WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Invalid Where Clause", async () => { + const query = "SELECT id, name FROM student WHERE age 30 AND name = John"; + expect(() => { + parseSelectQuery(query); + }).toThrowError("Invalid WHERE clause format"); +}); diff --git a/tests/step-07/index.test.js b/tests/step-07/index.test.js index ee0ebed5e..aaa243eeb 100644 --- a/tests/step-07/index.test.js +++ b/tests/step-07/index.test.js @@ -1,93 +1,170 @@ -const readCSV = require('../../src/csvReader'); -const parseQuery = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); -test('Read CSV File', async () => { - const data = await readCSV('./sample.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(3); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later }); -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM sample'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'sample', - whereClauses: [] - }); +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM sample'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); }); -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM sample WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'sample', - whereClauses: [{ - field: "age", - operator: "=", - value: "25", - }], - }); +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM sample WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); }); -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM sample WHERE age = 30 AND name = John'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'sample', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }] - }); +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query with Multiple WHERE Clause', async () => { - const query = 'SELECT id, name FROM sample WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); +test("Execute SQL Query with Multiple WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); }); -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM sample WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(2); - expect(result[0]).toHaveProperty('id'); +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); }); -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM sample WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(2); - expect(result[0]).toHaveProperty('name'); -}); \ No newline at end of file +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with unsupported operator", async () => { + const query = "SELECT name FROM student WHERE age <> 22"; + const parsedQuery = parseSelectQuery(query); + expect(parsedQuery).toEqual({ + fields: ["name"], + table: "student", + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + whereClauses: [ + { + field: "age", + operator: "<", + value: "> 22", + }, + ], + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query with incomplete WHERE Clause", async () => { + const query = "SELECT id FROM student WHERE age > 22 AND"; + const parsedQuery = parseSelectQuery(query); + expect(parsedQuery).toEqual({ + fields: ["id"], + table: "student", + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + whereClauses: [ + { + field: "age", + operator: ">", + value: "22 AND", + }, + ], + limit: null, + isDistinct: false, + }); +}); diff --git a/tests/step-08/index.test.js b/tests/step-08/index.test.js index aab1467e6..940a9f2a8 100644 --- a/tests/step-08/index.test.js +++ b/tests/step-08/index.test.js @@ -1,131 +1,169 @@ -const readCSV = require('../../src/csvReader'); -const parseQuery = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(3); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later }); -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null - }); +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); }); -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null - }); +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); }); -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null - }); +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); }); -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(2); - expect(result[0]).toHaveProperty('id'); +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); }); -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(2); - expect(result[0]).toHaveProperty('name'); +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); }); -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' } - }) +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + limit: null, + isDistinct: false, + }); }); -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' } - }) +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinType: "INNER", + limit: null, + isDistinct: false, + }); }); -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -133,18 +171,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -158,10 +199,12 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); \ No newline at end of file + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); +}); diff --git a/tests/step-09/index.test.js b/tests/step-09/index.test.js index aaf711f5a..b4b71bcf4 100644 --- a/tests/step-09/index.test.js +++ b/tests/step-09/index.test.js @@ -1,136 +1,169 @@ -const readCSV = require('../../src/csvReader'); -const {parseQuery} = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); - -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(4); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); - -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null, - joinType: null - }); -}); - -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null, - joinType: null - }); -}); - -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); - -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null, - joinType: null - }); -}); - -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('id'); -}); - -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('name'); -}); - -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - joinType: 'INNER' - }) +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later }); -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - joinType: 'INNER' - }) +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + isDistinct: false, + joinType: null, + limit: null, + }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + joinCondition: null, + joinTable: null, + joinType: null, + isDistinct: false, + limit: null, + }); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); }); -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinType: "INNER", + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinType: "INNER", + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -138,18 +171,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -163,30 +199,108 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); \ No newline at end of file + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": null, + "enrollment.course": "Biology", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); diff --git a/tests/step-10/index.test.js b/tests/step-10/index.test.js index 5e118eda5..6cd47c85a 100644 --- a/tests/step-10/index.test.js +++ b/tests/step-10/index.test.js @@ -1,59 +1,60 @@ -const readCSV = require('../../src/csvReader'); -const {parseQuery, parseJoinClause} = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); - -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(4); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); - -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); - -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('id'); -}); - -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('name'); -}); - -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -61,18 +62,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -86,531 +90,655 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); - -test('Execute SQL Query with RIGHT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": null, "enrollment.course": "Biology" }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "John" }), - expect.objectContaining({ "enrollment.course": "Physics", "student.name": "John" }) - ])); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "John", "enrollment.course": "Physics" }) - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "Bob" }), - expect.objectContaining({ "enrollment.course": "Biology", "student.name": null }) - ])); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Chemistry", "student.name": "Jane" }), - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; - const result = await executeSELECTQuery(query); - expect(result).toEqual([]); -}); - -test('Execute COUNT Aggregate Query', async () => { - const query = 'SELECT COUNT(*) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'COUNT(*)': 4 }]); -}); - -test('Execute SUM Aggregate Query', async () => { - const query = 'SELECT SUM(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'SUM(age)': 101 }]); -}); - -test('Execute AVG Aggregate Query', async () => { - const query = 'SELECT AVG(age) FROM student'; - const result = await executeSELECTQuery(query); - // Assuming AVG returns a single decimal point value - expect(result).toEqual([{ 'AVG(age)': 25.25 }]); -}); - -test('Execute MIN Aggregate Query', async () => { - const query = 'SELECT MIN(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MIN(age)': 22 }]); -}); - -test('Execute MAX Aggregate Query', async () => { - const query = 'SELECT MAX(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MAX(age)': 30 }]); -}); - -test('Count students per age', async () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '22', 'COUNT(*)': 1 }, - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments per course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 }, - { course: 'Physics', 'COUNT(*)': 1 }, - { course: 'Chemistry', 'COUNT(*)': 1 }, - { course: 'Biology', 'COUNT(*)': 1 } - ]); -}); - - -test('Count courses per student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 }, - { student_id: '2', 'COUNT(*)': 1 }, - { student_id: '3', 'COUNT(*)': 1 }, - { student_id: '5', 'COUNT(*)': 1 } - ]); -}); - -test('Count students within a specific age range', async () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments for a specific course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 } - ]); -}); - -test('Count courses for a specific student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 } - ]); -}); - -test('Average age of students above a certain age', async () => { - const query = 'SELECT AVG(age) FROM student WHERE age > 22'; - const result = await executeSELECTQuery(query); - const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 - expect(result).toEqual([{ 'AVG(age)': expectedAverage }]); -}); - -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - }); -}); - -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - }); -}); - -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - }); -}); - -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - }) -}); - -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", }) + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": null, + "enrollment.course": "Biology", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "enrollment.course": "Physics", + "student.name": "John", + }), + ]) + ); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Physics", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); + +test("Execute COUNT Aggregate Query", async () => { + const query = "SELECT COUNT(*) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "COUNT(*)": 4 }]); +}); + +test("Execute SUM Aggregate Query", async () => { + const query = "SELECT SUM(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "SUM(age)": 101 }]); +}); + +test("Execute AVG Aggregate Query", async () => { + const query = "SELECT AVG(age) FROM student"; + const result = await executeSELECTQuery(query); + // Assuming AVG returns a single decimal point value + expect(result).toEqual([{ "AVG(age)": 25.25 }]); +}); + +test("Execute MIN Aggregate Query", async () => { + const query = "SELECT MIN(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MIN(age)": 22 }]); +}); + +test("Execute MAX Aggregate Query", async () => { + const query = "SELECT MAX(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MAX(age)": 30 }]); +}); + +test("Count students per age", async () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "22", "COUNT(*)": 1 }, + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments per course", async () => { + const query = "SELECT course, COUNT(*) FROM enrollment GROUP BY course"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { course: "Mathematics", "COUNT(*)": 2 }, + { course: "Physics", "COUNT(*)": 1 }, + { course: "Chemistry", "COUNT(*)": 1 }, + { course: "Biology", "COUNT(*)": 1 }, + ]); +}); + +test("Count courses per student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { student_id: "1", "COUNT(*)": 2 }, + { student_id: "2", "COUNT(*)": 1 }, + { student_id: "3", "COUNT(*)": 1 }, + { student_id: "5", "COUNT(*)": 1 }, + ]); +}); + +test("Count students within a specific age range", async () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments for a specific course", async () => { + const query = + 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ course: "Mathematics", "COUNT(*)": 2 }]); +}); + +test("Count courses for a specific student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ student_id: "1", "COUNT(*)": 2 }]); +}); + +test("Average age of students above a certain age", async () => { + const query = "SELECT AVG(age) FROM student WHERE age > 22"; + const result = await executeSELECTQuery(query); + const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 + expect(result).toEqual([{ "AVG(age)": expectedAverage }]); +}); + +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse INNER JOIN clause", () => { + const query = + "SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "INNER", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse LEFT JOIN clause", () => { + const query = + "SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "LEFT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse RIGHT JOIN clause", () => { + const query = + "SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "RIGHT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Returns null for queries without JOIN", () => { + const query = "SELECT * FROM table1"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: null, + joinTable: null, + joinCondition: null, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "LEFT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "RIGHT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "22" }], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Physics'" }, + ], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [{ field: "student.age", operator: "<", value: "25" }], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Chemistry'" }, + ], + groupByFields: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse COUNT Aggregate Query", () => { + const query = "SELECT COUNT(*) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + orderByFields: null, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SUM Aggregate Query", () => { + const query = "SELECT SUM(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["SUM(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + orderByFields: null, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse AVG Aggregate Query", () => { + const query = "SELECT AVG(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["AVG(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + orderByFields: null, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MIN Aggregate Query", () => { + const query = "SELECT MIN(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MIN(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + orderByFields: null, + joinCondition: null, + joinTable: null, + joinType: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MAX Aggregate Query", () => { + const query = "SELECT MAX(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MAX(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + orderByFields: null, + joinType: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse basic GROUP BY query", () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with WHERE clause", () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [{ field: "age", operator: ">", value: "22" }], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with multiple fields", () => { + const query = + "SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course", "COUNT(*)"], + table: "enrollment", + whereClauses: [], + groupByFields: ["student_id", "course"], + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + hasAggregateWithoutGroupBy: false, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with JOIN and WHERE clauses", () => { + const query = + 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name", "COUNT(*)"], + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: '"Mathematics"' }, + ], + groupByFields: ["student.name"], + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); }); - -test('Parse INNER JOIN clause', () => { - const query = 'SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'INNER', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' }, - }); -}); - -test('Parse LEFT JOIN clause', () => { - const query = 'SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'LEFT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Parse RIGHT JOIN clause', () => { - const query = 'SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'RIGHT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Returns null for queries without JOIN', () => { - const query = 'SELECT * FROM table1'; - const result = parseJoinClause(query); - expect(result).toEqual( - { - joinType: null, - joinTable: null, - joinCondition: null - } - ); -}); - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'LEFT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - }) -}) - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'RIGHT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - }) -}) - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - }); -}); - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - }); -}); - - -test('Parse COUNT Aggregate Query', () => { - const query = 'SELECT COUNT(*) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - }); -}); - - -test('Parse SUM Aggregate Query', () => { - const query = 'SELECT SUM(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['SUM(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - }); -}); - -test('Parse AVG Aggregate Query', () => { - const query = 'SELECT AVG(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['AVG(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - }); -}); - -test('Parse MIN Aggregate Query', () => { - const query = 'SELECT MIN(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MIN(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - }); -}); - -test('Parse MAX Aggregate Query', () => { - const query = 'SELECT MAX(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MAX(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - }); -}); - -test('Parse basic GROUP BY query', () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false - }); -}); - -test('Parse GROUP BY query with WHERE clause', () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'age', operator: '>', value: '22' }], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false - }); -}); - -test('Parse GROUP BY query with multiple fields', () => { - const query = 'SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student_id', 'course', 'COUNT(*)'], - table: 'enrollment', - whereClauses: [], - groupByFields: ['student_id', 'course'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false - }); -}); - -test('Parse GROUP BY query with JOIN and WHERE clauses', () => { - const query = 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student.name', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'enrollment.course', operator: '=', value: '"Mathematics"' }], - groupByFields: ['student.name'], - joinType: 'INNER', - joinTable: 'enrollment', - joinCondition: { - left: 'student.id', - right: 'enrollment.student_id' - }, - hasAggregateWithoutGroupBy: false - }); -}); \ No newline at end of file diff --git a/tests/step-11/index.test.js b/tests/step-11/index.test.js index 1cf5f2def..5b39bb88f 100644 --- a/tests/step-11/index.test.js +++ b/tests/step-11/index.test.js @@ -1,59 +1,60 @@ -const readCSV = require('../../src/csvReader'); -const {parseQuery, parseJoinClause} = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); - -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(4); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); - -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); - -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('id'); -}); - -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('name'); -}); - -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -61,18 +62,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -86,584 +90,706 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); - -test('Execute SQL Query with RIGHT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": null, "enrollment.course": "Biology" }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "John" }), - expect.objectContaining({ "enrollment.course": "Physics", "student.name": "John" }) - ])); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "John", "enrollment.course": "Physics" }) - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "Bob" }), - expect.objectContaining({ "enrollment.course": "Biology", "student.name": null }) - ])); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Chemistry", "student.name": "Jane" }), - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; - const result = await executeSELECTQuery(query); - expect(result).toEqual([]); -}); - -test('Execute COUNT Aggregate Query', async () => { - const query = 'SELECT COUNT(*) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'COUNT(*)': 4 }]); -}); - -test('Execute SUM Aggregate Query', async () => { - const query = 'SELECT SUM(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'SUM(age)': 101 }]); -}); - -test('Execute AVG Aggregate Query', async () => { - const query = 'SELECT AVG(age) FROM student'; - const result = await executeSELECTQuery(query); - // Assuming AVG returns a single decimal point value - expect(result).toEqual([{ 'AVG(age)': 25.25 }]); -}); - -test('Execute MIN Aggregate Query', async () => { - const query = 'SELECT MIN(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MIN(age)': 22 }]); -}); - -test('Execute MAX Aggregate Query', async () => { - const query = 'SELECT MAX(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MAX(age)': 30 }]); -}); - -test('Count students per age', async () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '22', 'COUNT(*)': 1 }, - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments per course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 }, - { course: 'Physics', 'COUNT(*)': 1 }, - { course: 'Chemistry', 'COUNT(*)': 1 }, - { course: 'Biology', 'COUNT(*)': 1 } - ]); -}); - - -test('Count courses per student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 }, - { student_id: '2', 'COUNT(*)': 1 }, - { student_id: '3', 'COUNT(*)': 1 }, - { student_id: '5', 'COUNT(*)': 1 } - ]); -}); - -test('Count students within a specific age range', async () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments for a specific course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 } - ]); -}); - -test('Count courses for a specific student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 } - ]); -}); - -test('Average age of students above a certain age', async () => { - const query = 'SELECT AVG(age) FROM student WHERE age > 22'; - const result = await executeSELECTQuery(query); - const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 - expect(result).toEqual([{ 'AVG(age)': expectedAverage }]); -}); - -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null - }); -}); - -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null - }); -}); - -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null - }); -}); - -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null - }) -}); - -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", }) + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": null, + "enrollment.course": "Biology", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "enrollment.course": "Physics", + "student.name": "John", + }), + ]) + ); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Physics", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); + +test("Execute COUNT Aggregate Query", async () => { + const query = "SELECT COUNT(*) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "COUNT(*)": 4 }]); +}); + +test("Execute SUM Aggregate Query", async () => { + const query = "SELECT SUM(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "SUM(age)": 101 }]); +}); + +test("Execute AVG Aggregate Query", async () => { + const query = "SELECT AVG(age) FROM student"; + const result = await executeSELECTQuery(query); + // Assuming AVG returns a single decimal point value + expect(result).toEqual([{ "AVG(age)": 25.25 }]); +}); + +test("Execute MIN Aggregate Query", async () => { + const query = "SELECT MIN(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MIN(age)": 22 }]); +}); + +test("Execute MAX Aggregate Query", async () => { + const query = "SELECT MAX(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MAX(age)": 30 }]); +}); + +test("Count students per age", async () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "22", "COUNT(*)": 1 }, + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments per course", async () => { + const query = "SELECT course, COUNT(*) FROM enrollment GROUP BY course"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { course: "Mathematics", "COUNT(*)": 2 }, + { course: "Physics", "COUNT(*)": 1 }, + { course: "Chemistry", "COUNT(*)": 1 }, + { course: "Biology", "COUNT(*)": 1 }, + ]); +}); + +test("Count courses per student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { student_id: "1", "COUNT(*)": 2 }, + { student_id: "2", "COUNT(*)": 1 }, + { student_id: "3", "COUNT(*)": 1 }, + { student_id: "5", "COUNT(*)": 1 }, + ]); +}); + +test("Count students within a specific age range", async () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments for a specific course", async () => { + const query = + 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ course: "Mathematics", "COUNT(*)": 2 }]); +}); + +test("Count courses for a specific student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ student_id: "1", "COUNT(*)": 2 }]); +}); + +test("Average age of students above a certain age", async () => { + const query = "SELECT AVG(age) FROM student WHERE age > 22"; + const result = await executeSELECTQuery(query); + const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 + expect(result).toEqual([{ "AVG(age)": expectedAverage }]); +}); + +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + isDistinct: false, + limit: null, + }); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse INNER JOIN clause", () => { + const query = + "SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "INNER", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse LEFT JOIN clause", () => { + const query = + "SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "LEFT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse RIGHT JOIN clause", () => { + const query = + "SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "RIGHT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Returns null for queries without JOIN", () => { + const query = "SELECT * FROM table1"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: null, + joinTable: null, + joinCondition: null, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "LEFT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "RIGHT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "22" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Physics'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [{ field: "student.age", operator: "<", value: "25" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Chemistry'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse COUNT Aggregate Query", () => { + const query = "SELECT COUNT(*) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SUM Aggregate Query", () => { + const query = "SELECT SUM(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["SUM(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + isDistinct: false, + limit: null, + }); +}); + +test("Parse AVG Aggregate Query", () => { + const query = "SELECT AVG(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["AVG(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + isDistinct: false, + limit: null, + }); +}); + +test("Parse MIN Aggregate Query", () => { + const query = "SELECT MIN(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MIN(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MAX Aggregate Query", () => { + const query = "SELECT MAX(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MAX(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse basic GROUP BY query", () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with WHERE clause", () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [{ field: "age", operator: ">", value: "22" }], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with multiple fields", () => { + const query = + "SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course", "COUNT(*)"], + table: "enrollment", + whereClauses: [], + groupByFields: ["student_id", "course"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with JOIN and WHERE clauses", () => { + const query = + 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name", "COUNT(*)"], + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: '"Mathematics"' }, + ], + groupByFields: ["student.name"], + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query with ORDER BY", async () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { name: "Alice" }, + { name: "Bob" }, + { name: "Jane" }, + { name: "John" }, + ]); +}); + +test("Execute SQL Query with ORDER BY and WHERE", async () => { + const query = "SELECT name FROM student WHERE age > 24 ORDER BY name DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([{ name: "John" }, { name: "Jane" }]); +}); +test("Execute SQL Query with ORDER BY and GROUP BY", async () => { + const query = + "SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC"; + const result = await executeSELECTQuery(query); + expect(result).toStrictEqual([ + { age: "30", "COUNT(id) as count": 1 }, + { age: "25", "COUNT(id) as count": 1 }, + { age: "24", "COUNT(id) as count": 1 }, + { age: "22", "COUNT(id) as count": 1 }, + ]); +}); + +test("Parse SQL Query with ORDER BY", () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const parsed = parseSelectQuery(query); + expect(parsed.orderByFields).toEqual([{ fieldName: "name", order: "ASC" }]); +}); + +test("Parse SQL Query with ORDER BY and WHERE", () => { + const query = "SELECT name FROM student WHERE age > 20 ORDER BY name DESC"; + const parsed = parseSelectQuery(query); + expect(parsed.orderByFields).toEqual([{ fieldName: "name", order: "DESC" }]); + expect(parsed.whereClauses.length).toBeGreaterThan(0); +}); + +test("Parse SQL Query with ORDER BY and GROUP BY", () => { + const query = + "SELECT COUNT(id), age FROM student GROUP BY age ORDER BY age DESC"; + const parsed = parseSelectQuery(query); + expect(parsed.orderByFields).toEqual([{ fieldName: "age", order: "DESC" }]); + expect(parsed.groupByFields).toEqual(["age"]); }); - -test('Parse INNER JOIN clause', () => { - const query = 'SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'INNER', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' }, - }); -}); - -test('Parse LEFT JOIN clause', () => { - const query = 'SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'LEFT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Parse RIGHT JOIN clause', () => { - const query = 'SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'RIGHT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Returns null for queries without JOIN', () => { - const query = 'SELECT * FROM table1'; - const result = parseJoinClause(query); - expect(result).toEqual( - { - joinType: null, - joinTable: null, - joinCondition: null - } - ); -}); - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'LEFT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null - }) -}) - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'RIGHT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null - }) -}) - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null - }); -}); - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null - }); -}); - - -test('Parse COUNT Aggregate Query', () => { - const query = 'SELECT COUNT(*) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null - }); -}); - - -test('Parse SUM Aggregate Query', () => { - const query = 'SELECT SUM(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['SUM(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null - }); -}); - -test('Parse AVG Aggregate Query', () => { - const query = 'SELECT AVG(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['AVG(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null - }); -}); - -test('Parse MIN Aggregate Query', () => { - const query = 'SELECT MIN(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MIN(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null - }); -}); - -test('Parse MAX Aggregate Query', () => { - const query = 'SELECT MAX(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MAX(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null - }); -}); - -test('Parse basic GROUP BY query', () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null - }); -}); - -test('Parse GROUP BY query with WHERE clause', () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'age', operator: '>', value: '22' }], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null - }); -}); - -test('Parse GROUP BY query with multiple fields', () => { - const query = 'SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student_id', 'course', 'COUNT(*)'], - table: 'enrollment', - whereClauses: [], - groupByFields: ['student_id', 'course'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null - }); -}); - -test('Parse GROUP BY query with JOIN and WHERE clauses', () => { - const query = 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student.name', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'enrollment.course', operator: '=', value: '"Mathematics"' }], - groupByFields: ['student.name'], - joinType: 'INNER', - joinTable: 'enrollment', - joinCondition: { - left: 'student.id', - right: 'enrollment.student_id' - }, - hasAggregateWithoutGroupBy: false, - orderByFields: null - }); -}); - -test('Execute SQL Query with ORDER BY', async () => { - const query = 'SELECT name FROM student ORDER BY name ASC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Jane' }, - { name: 'John' } - ]); -}); - -test('Execute SQL Query with ORDER BY and WHERE', async () => { - const query = 'SELECT name FROM student WHERE age > 24 ORDER BY name DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'John' }, - { name: 'Jane' }, - ]); -}); -test('Execute SQL Query with ORDER BY and GROUP BY', async () => { - const query = 'SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { age: '30', 'COUNT(id) as count': 1 }, - { age: '25', 'COUNT(id) as count': 1 }, - { age: '24', 'COUNT(id) as count': 1 }, - { age: '22', 'COUNT(id) as count': 1 } - ]); -}); \ No newline at end of file diff --git a/tests/step-12/index.test.js b/tests/step-12/index.test.js index d15c77ef5..029db25e6 100644 --- a/tests/step-12/index.test.js +++ b/tests/step-12/index.test.js @@ -1,59 +1,60 @@ -const readCSV = require('../../src/csvReader'); -const {parseQuery, parseJoinClause} = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); - -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(4); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); - -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); - -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('id'); -}); - -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('name'); -}); - -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -61,18 +62,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -86,636 +90,719 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); - -test('Execute SQL Query with RIGHT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": null, "enrollment.course": "Biology" }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "John" }), - expect.objectContaining({ "enrollment.course": "Physics", "student.name": "John" }) - ])); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "John", "enrollment.course": "Physics" }) - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "Bob" }), - expect.objectContaining({ "enrollment.course": "Biology", "student.name": null }) - ])); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Chemistry", "student.name": "Jane" }), - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; - const result = await executeSELECTQuery(query); - expect(result).toEqual([]); -}); - -test('Execute COUNT Aggregate Query', async () => { - const query = 'SELECT COUNT(*) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'COUNT(*)': 4 }]); -}); - -test('Execute SUM Aggregate Query', async () => { - const query = 'SELECT SUM(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'SUM(age)': 101 }]); -}); - -test('Execute AVG Aggregate Query', async () => { - const query = 'SELECT AVG(age) FROM student'; - const result = await executeSELECTQuery(query); - // Assuming AVG returns a single decimal point value - expect(result).toEqual([{ 'AVG(age)': 25.25 }]); -}); - -test('Execute MIN Aggregate Query', async () => { - const query = 'SELECT MIN(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MIN(age)': 22 }]); -}); - -test('Execute MAX Aggregate Query', async () => { - const query = 'SELECT MAX(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MAX(age)': 30 }]); -}); - -test('Count students per age', async () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '22', 'COUNT(*)': 1 }, - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments per course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 }, - { course: 'Physics', 'COUNT(*)': 1 }, - { course: 'Chemistry', 'COUNT(*)': 1 }, - { course: 'Biology', 'COUNT(*)': 1 } - ]); -}); - - -test('Count courses per student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 }, - { student_id: '2', 'COUNT(*)': 1 }, - { student_id: '3', 'COUNT(*)': 1 }, - { student_id: '5', 'COUNT(*)': 1 } - ]); -}); - -test('Count students within a specific age range', async () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments for a specific course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 } - ]); -}); - -test('Count courses for a specific student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 } - ]); -}); - -test('Average age of students above a certain age', async () => { - const query = 'SELECT AVG(age) FROM student WHERE age > 22'; - const result = await executeSELECTQuery(query); - const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 - expect(result).toEqual([{ 'AVG(age)': expectedAverage }]); -}); - -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }) -}); - -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", }) + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": null, + "enrollment.course": "Biology", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "enrollment.course": "Physics", + "student.name": "John", + }), + ]) + ); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Physics", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); + +test("Execute COUNT Aggregate Query", async () => { + const query = "SELECT COUNT(*) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "COUNT(*)": 4 }]); +}); + +test("Execute SUM Aggregate Query", async () => { + const query = "SELECT SUM(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "SUM(age)": 101 }]); +}); + +test("Execute AVG Aggregate Query", async () => { + const query = "SELECT AVG(age) FROM student"; + const result = await executeSELECTQuery(query); + // Assuming AVG returns a single decimal point value + expect(result).toEqual([{ "AVG(age)": 25.25 }]); +}); + +test("Execute MIN Aggregate Query", async () => { + const query = "SELECT MIN(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MIN(age)": 22 }]); +}); + +test("Execute MAX Aggregate Query", async () => { + const query = "SELECT MAX(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MAX(age)": 30 }]); +}); + +test("Count students per age", async () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "22", "COUNT(*)": 1 }, + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments per course", async () => { + const query = "SELECT course, COUNT(*) FROM enrollment GROUP BY course"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { course: "Mathematics", "COUNT(*)": 2 }, + { course: "Physics", "COUNT(*)": 1 }, + { course: "Chemistry", "COUNT(*)": 1 }, + { course: "Biology", "COUNT(*)": 1 }, + ]); +}); + +test("Count courses per student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { student_id: "1", "COUNT(*)": 2 }, + { student_id: "2", "COUNT(*)": 1 }, + { student_id: "3", "COUNT(*)": 1 }, + { student_id: "5", "COUNT(*)": 1 }, + ]); +}); + +test("Count students within a specific age range", async () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments for a specific course", async () => { + const query = + 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ course: "Mathematics", "COUNT(*)": 2 }]); +}); + +test("Count courses for a specific student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ student_id: "1", "COUNT(*)": 2 }]); +}); + +test("Average age of students above a certain age", async () => { + const query = "SELECT AVG(age) FROM student WHERE age > 22"; + const result = await executeSELECTQuery(query); + const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 + expect(result).toEqual([{ "AVG(age)": expectedAverage }]); +}); + +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + isDistinct: false, + }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse INNER JOIN clause", () => { + const query = + "SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "INNER", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse LEFT JOIN clause", () => { + const query = + "SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "LEFT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse RIGHT JOIN clause", () => { + const query = + "SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "RIGHT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Returns null for queries without JOIN", () => { + const query = "SELECT * FROM table1"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: null, + joinTable: null, + joinCondition: null, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "LEFT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "RIGHT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "22" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Physics'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [{ field: "student.age", operator: "<", value: "25" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Chemistry'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + isDistinct: false, + limit: null, + }); +}); + +test("Parse COUNT Aggregate Query", () => { + const query = "SELECT COUNT(*) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + isDistinct: false, + limit: null, + }); +}); + +test("Parse SUM Aggregate Query", () => { + const query = "SELECT SUM(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["SUM(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + isDistinct: false, + orderByFields: null, + limit: null, + }); +}); + +test("Parse AVG Aggregate Query", () => { + const query = "SELECT AVG(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["AVG(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MIN Aggregate Query", () => { + const query = "SELECT MIN(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MIN(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MAX Aggregate Query", () => { + const query = "SELECT MAX(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MAX(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse basic GROUP BY query", () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with WHERE clause", () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [{ field: "age", operator: ">", value: "22" }], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with multiple fields", () => { + const query = + "SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course", "COUNT(*)"], + table: "enrollment", + whereClauses: [], + groupByFields: ["student_id", "course"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with JOIN and WHERE clauses", () => { + const query = + 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name", "COUNT(*)"], + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: '"Mathematics"' }, + ], + groupByFields: ["student.name"], + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query with ORDER BY", async () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { name: "Alice" }, + { name: "Bob" }, + { name: "Jane" }, + { name: "John" }, + ]); +}); + +test("Execute SQL Query with ORDER BY and WHERE", async () => { + const query = "SELECT name FROM student WHERE age > 24 ORDER BY name DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([{ name: "John" }, { name: "Jane" }]); +}); +test("Execute SQL Query with ORDER BY and GROUP BY", async () => { + const query = + "SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { age: "30", "COUNT(id) as count": 1 }, + { age: "25", "COUNT(id) as count": 1 }, + { age: "24", "COUNT(id) as count": 1 }, + { age: "22", "COUNT(id) as count": 1 }, + ]); +}); + +test("Execute SQL Query with standard LIMIT clause", async () => { + const query = "SELECT id, name FROM student LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with LIMIT clause equal to total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 4"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LIMIT clause exceeding total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 10"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); // Total rows in student.csv +}); + +test("Execute SQL Query with LIMIT 0", async () => { + const query = "SELECT id, name FROM student LIMIT 0"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(0); +}); + +test("Execute SQL Query with LIMIT and ORDER BY clause", async () => { + const query = "SELECT id, name FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); + expect(result[0].name).toEqual("John"); + expect(result[1].name).toEqual("Jane"); }); - -test('Parse INNER JOIN clause', () => { - const query = 'SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'INNER', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' }, - }); -}); - -test('Parse LEFT JOIN clause', () => { - const query = 'SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'LEFT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Parse RIGHT JOIN clause', () => { - const query = 'SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'RIGHT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Returns null for queries without JOIN', () => { - const query = 'SELECT * FROM table1'; - const result = parseJoinClause(query); - expect(result).toEqual( - { - joinType: null, - joinTable: null, - joinCondition: null - } - ); -}); - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'LEFT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }) -}) - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'RIGHT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }) -}) - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - - -test('Parse COUNT Aggregate Query', () => { - const query = 'SELECT COUNT(*) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null - }); -}); - - -test('Parse SUM Aggregate Query', () => { - const query = 'SELECT SUM(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['SUM(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse AVG Aggregate Query', () => { - const query = 'SELECT AVG(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['AVG(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse MIN Aggregate Query', () => { - const query = 'SELECT MIN(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MIN(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse MAX Aggregate Query', () => { - const query = 'SELECT MAX(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MAX(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse basic GROUP BY query', () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null - }); -}); - -test('Parse GROUP BY query with WHERE clause', () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'age', operator: '>', value: '22' }], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null - }); -}); - -test('Parse GROUP BY query with multiple fields', () => { - const query = 'SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student_id', 'course', 'COUNT(*)'], - table: 'enrollment', - whereClauses: [], - groupByFields: ['student_id', 'course'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null - }); -}); - -test('Parse GROUP BY query with JOIN and WHERE clauses', () => { - const query = 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student.name', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'enrollment.course', operator: '=', value: '"Mathematics"' }], - groupByFields: ['student.name'], - joinType: 'INNER', - joinTable: 'enrollment', - joinCondition: { - left: 'student.id', - right: 'enrollment.student_id' - }, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - }); -}); - -test('Execute SQL Query with ORDER BY', async () => { - const query = 'SELECT name FROM student ORDER BY name ASC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Jane' }, - { name: 'John' } - ]); -}); - -test('Execute SQL Query with ORDER BY and WHERE', async () => { - const query = 'SELECT name FROM student WHERE age > 24 ORDER BY name DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'John' }, - { name: 'Jane' }, - ]); -}); -test('Execute SQL Query with ORDER BY and GROUP BY', async () => { - const query = 'SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { age: '30', 'COUNT(id) as count': 1 }, - { age: '25', 'COUNT(id) as count': 1 }, - { age: '24', 'COUNT(id) as count': 1 }, - { age: '22', 'COUNT(id) as count': 1 } - ]); -}); - -test('Execute SQL Query with standard LIMIT clause', async () => { - const query = 'SELECT id, name FROM student LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with LIMIT clause equal to total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 4'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LIMIT clause exceeding total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 10'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); // Total rows in student.csv -}); - -test('Execute SQL Query with LIMIT 0', async () => { - const query = 'SELECT id, name FROM student LIMIT 0'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(0); -}); - -test('Execute SQL Query with LIMIT and ORDER BY clause', async () => { - const query = 'SELECT id, name FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); - expect(result[0].name).toEqual('John'); - expect(result[1].name).toEqual('Jane'); -}); \ No newline at end of file diff --git a/tests/step-13/index.test.js b/tests/step-13/index.test.js index 0797faaba..0224f14ac 100644 --- a/tests/step-13/index.test.js +++ b/tests/step-13/index.test.js @@ -1,59 +1,60 @@ -const readCSV = require('../../src/csvReader'); -const {parseQuery, parseJoinClause} = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); - -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(4); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); - -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); - -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('id'); -}); - -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('name'); -}); - -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -61,18 +62,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -86,641 +90,725 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); - -test('Execute SQL Query with RIGHT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": null, "enrollment.course": "Biology" }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "John" }), - expect.objectContaining({ "enrollment.course": "Physics", "student.name": "John" }) - ])); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "John", "enrollment.course": "Physics" }) - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "Bob" }), - expect.objectContaining({ "enrollment.course": "Biology", "student.name": null }) - ])); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Chemistry", "student.name": "Jane" }), - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; - const result = await executeSELECTQuery(query); - expect(result).toEqual([]); -}); - -test('Execute COUNT Aggregate Query', async () => { - const query = 'SELECT COUNT(*) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'COUNT(*)': 4 }]); -}); - -test('Execute SUM Aggregate Query', async () => { - const query = 'SELECT SUM(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'SUM(age)': 101 }]); -}); - -test('Execute AVG Aggregate Query', async () => { - const query = 'SELECT AVG(age) FROM student'; - const result = await executeSELECTQuery(query); - // Assuming AVG returns a single decimal point value - expect(result).toEqual([{ 'AVG(age)': 25.25 }]); -}); - -test('Execute MIN Aggregate Query', async () => { - const query = 'SELECT MIN(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MIN(age)': 22 }]); -}); - -test('Execute MAX Aggregate Query', async () => { - const query = 'SELECT MAX(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MAX(age)': 30 }]); -}); - -test('Count students per age', async () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '22', 'COUNT(*)': 1 }, - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments per course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 }, - { course: 'Physics', 'COUNT(*)': 1 }, - { course: 'Chemistry', 'COUNT(*)': 1 }, - { course: 'Biology', 'COUNT(*)': 1 } - ]); -}); - - -test('Count courses per student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 }, - { student_id: '2', 'COUNT(*)': 1 }, - { student_id: '3', 'COUNT(*)': 1 }, - { student_id: '5', 'COUNT(*)': 1 } - ]); -}); - -test('Count students within a specific age range', async () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments for a specific course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 } - ]); -}); - -test('Count courses for a specific student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 } - ]); -}); - -test('Average age of students above a certain age', async () => { - const query = 'SELECT AVG(age) FROM student WHERE age > 22'; - const result = await executeSELECTQuery(query); - const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 - expect(result).toEqual([{ 'AVG(age)': expectedAverage }]); -}); - -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }) -}); - -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", }) + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": null, + "enrollment.course": "Biology", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "enrollment.course": "Physics", + "student.name": "John", + }), + ]) + ); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Physics", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); + +test("Execute COUNT Aggregate Query", async () => { + const query = "SELECT COUNT(*) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "COUNT(*)": 4 }]); +}); + +test("Execute SUM Aggregate Query", async () => { + const query = "SELECT SUM(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "SUM(age)": 101 }]); +}); + +test("Execute AVG Aggregate Query", async () => { + const query = "SELECT AVG(age) FROM student"; + const result = await executeSELECTQuery(query); + // Assuming AVG returns a single decimal point value + expect(result).toEqual([{ "AVG(age)": 25.25 }]); +}); + +test("Execute MIN Aggregate Query", async () => { + const query = "SELECT MIN(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MIN(age)": 22 }]); +}); + +test("Execute MAX Aggregate Query", async () => { + const query = "SELECT MAX(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MAX(age)": 30 }]); +}); + +test("Count students per age", async () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "22", "COUNT(*)": 1 }, + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments per course", async () => { + const query = "SELECT course, COUNT(*) FROM enrollment GROUP BY course"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { course: "Mathematics", "COUNT(*)": 2 }, + { course: "Physics", "COUNT(*)": 1 }, + { course: "Chemistry", "COUNT(*)": 1 }, + { course: "Biology", "COUNT(*)": 1 }, + ]); +}); + +test("Count courses per student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { student_id: "1", "COUNT(*)": 2 }, + { student_id: "2", "COUNT(*)": 1 }, + { student_id: "3", "COUNT(*)": 1 }, + { student_id: "5", "COUNT(*)": 1 }, + ]); +}); + +test("Count students within a specific age range", async () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments for a specific course", async () => { + const query = + 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ course: "Mathematics", "COUNT(*)": 2 }]); +}); + +test("Count courses for a specific student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ student_id: "1", "COUNT(*)": 2 }]); +}); + +test("Average age of students above a certain age", async () => { + const query = "SELECT AVG(age) FROM student WHERE age > 22"; + const result = await executeSELECTQuery(query); + const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 + expect(result).toEqual([{ "AVG(age)": expectedAverage }]); +}); + +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse INNER JOIN clause", () => { + const query = + "SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "INNER", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse LEFT JOIN clause", () => { + const query = + "SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "LEFT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse RIGHT JOIN clause", () => { + const query = + "SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "RIGHT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Returns null for queries without JOIN", () => { + const query = "SELECT * FROM table1"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: null, + joinTable: null, + joinCondition: null, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "LEFT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "RIGHT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "22" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Physics'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [{ field: "student.age", operator: "<", value: "25" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Chemistry'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse COUNT Aggregate Query", () => { + const query = "SELECT COUNT(*) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SUM Aggregate Query", () => { + const query = "SELECT SUM(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["SUM(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse AVG Aggregate Query", () => { + const query = "SELECT AVG(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["AVG(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MIN Aggregate Query", () => { + const query = "SELECT MIN(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MIN(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MAX Aggregate Query", () => { + const query = "SELECT MAX(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MAX(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse basic GROUP BY query", () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with WHERE clause", () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [{ field: "age", operator: ">", value: "22" }], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with multiple fields", () => { + const query = + "SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course", "COUNT(*)"], + table: "enrollment", + whereClauses: [], + groupByFields: ["student_id", "course"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with JOIN and WHERE clauses", () => { + const query = + 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name", "COUNT(*)"], + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: '"Mathematics"' }, + ], + groupByFields: ["student.name"], + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query with ORDER BY", async () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { name: "Alice" }, + { name: "Bob" }, + { name: "Jane" }, + { name: "John" }, + ]); +}); + +test("Execute SQL Query with ORDER BY and WHERE", async () => { + const query = "SELECT name FROM student WHERE age > 24 ORDER BY name DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([{ name: "John" }, { name: "Jane" }]); +}); +test("Execute SQL Query with ORDER BY and GROUP BY", async () => { + const query = + "SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { age: "30", "COUNT(id) as count": 1 }, + { age: "25", "COUNT(id) as count": 1 }, + { age: "24", "COUNT(id) as count": 1 }, + { age: "22", "COUNT(id) as count": 1 }, + ]); +}); + +test("Execute SQL Query with standard LIMIT clause", async () => { + const query = "SELECT id, name FROM student LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with LIMIT clause equal to total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 4"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LIMIT clause exceeding total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 10"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); // Total rows in student.csv +}); + +test("Execute SQL Query with LIMIT 0", async () => { + const query = "SELECT id, name FROM student LIMIT 0"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(0); +}); + +test("Execute SQL Query with LIMIT and ORDER BY clause", async () => { + const query = "SELECT id, name FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); + expect(result[0].name).toEqual("John"); + expect(result[1].name).toEqual("Jane"); +}); + +test("Error Handling with Malformed Query", async () => { + const query = "SELECT FROM table"; // intentionally malformed + await expect(executeSELECTQuery(query)).rejects.toThrow( + "Error executing query: Query parsing error: Invalid SELECT format" + ); }); - -test('Parse INNER JOIN clause', () => { - const query = 'SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'INNER', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' }, - }); -}); - -test('Parse LEFT JOIN clause', () => { - const query = 'SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'LEFT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Parse RIGHT JOIN clause', () => { - const query = 'SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'RIGHT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Returns null for queries without JOIN', () => { - const query = 'SELECT * FROM table1'; - const result = parseJoinClause(query); - expect(result).toEqual( - { - joinType: null, - joinTable: null, - joinCondition: null - } - ); -}); - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'LEFT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }) -}) - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'RIGHT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }) -}) - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null - }); -}); - - -test('Parse COUNT Aggregate Query', () => { - const query = 'SELECT COUNT(*) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null - }); -}); - - -test('Parse SUM Aggregate Query', () => { - const query = 'SELECT SUM(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['SUM(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse AVG Aggregate Query', () => { - const query = 'SELECT AVG(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['AVG(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse MIN Aggregate Query', () => { - const query = 'SELECT MIN(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MIN(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse MAX Aggregate Query', () => { - const query = 'SELECT MAX(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MAX(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null - }); -}); - -test('Parse basic GROUP BY query', () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null - }); -}); - -test('Parse GROUP BY query with WHERE clause', () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'age', operator: '>', value: '22' }], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null - }); -}); - -test('Parse GROUP BY query with multiple fields', () => { - const query = 'SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student_id', 'course', 'COUNT(*)'], - table: 'enrollment', - whereClauses: [], - groupByFields: ['student_id', 'course'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null - }); -}); - -test('Parse GROUP BY query with JOIN and WHERE clauses', () => { - const query = 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student.name', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'enrollment.course', operator: '=', value: '"Mathematics"' }], - groupByFields: ['student.name'], - joinType: 'INNER', - joinTable: 'enrollment', - joinCondition: { - left: 'student.id', - right: 'enrollment.student_id' - }, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - }); -}); - -test('Execute SQL Query with ORDER BY', async () => { - const query = 'SELECT name FROM student ORDER BY name ASC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Jane' }, - { name: 'John' } - ]); -}); - -test('Execute SQL Query with ORDER BY and WHERE', async () => { - const query = 'SELECT name FROM student WHERE age > 24 ORDER BY name DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'John' }, - { name: 'Jane' }, - ]); -}); -test('Execute SQL Query with ORDER BY and GROUP BY', async () => { - const query = 'SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { age: '30', 'COUNT(id) as count': 1 }, - { age: '25', 'COUNT(id) as count': 1 }, - { age: '24', 'COUNT(id) as count': 1 }, - { age: '22', 'COUNT(id) as count': 1 } - ]); -}); - -test('Execute SQL Query with standard LIMIT clause', async () => { - const query = 'SELECT id, name FROM student LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with LIMIT clause equal to total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 4'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LIMIT clause exceeding total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 10'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); // Total rows in student.csv -}); - -test('Execute SQL Query with LIMIT 0', async () => { - const query = 'SELECT id, name FROM student LIMIT 0'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(0); -}); - -test('Execute SQL Query with LIMIT and ORDER BY clause', async () => { - const query = 'SELECT id, name FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); - expect(result[0].name).toEqual('John'); - expect(result[1].name).toEqual('Jane'); -}); - -test('Error Handling with Malformed Query', async () => { - const query = 'SELECT FROM table'; // intentionally malformed - await expect(executeSELECTQuery(query)).rejects.toThrow("Error executing query: Query parsing error: Invalid SELECT format"); -}); \ No newline at end of file diff --git a/tests/step-14/index.test.js b/tests/step-14/index.test.js index 502411fa7..a2f937e4f 100644 --- a/tests/step-14/index.test.js +++ b/tests/step-14/index.test.js @@ -1,59 +1,60 @@ -const readCSV = require('../../src/csvReader'); -const {parseQuery, parseJoinClause} = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); - -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(4); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); - -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); - -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('id'); -}); - -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('name'); -}); - -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -61,18 +62,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -86,702 +90,776 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); - -test('Execute SQL Query with RIGHT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": null, "enrollment.course": "Biology" }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "John" }), - expect.objectContaining({ "enrollment.course": "Physics", "student.name": "John" }) - ])); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "John", "enrollment.course": "Physics" }) - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "Bob" }), - expect.objectContaining({ "enrollment.course": "Biology", "student.name": null }) - ])); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Chemistry", "student.name": "Jane" }), - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; - const result = await executeSELECTQuery(query); - expect(result).toEqual([]); -}); - -test('Execute COUNT Aggregate Query', async () => { - const query = 'SELECT COUNT(*) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'COUNT(*)': 4 }]); -}); - -test('Execute SUM Aggregate Query', async () => { - const query = 'SELECT SUM(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'SUM(age)': 101 }]); -}); - -test('Execute AVG Aggregate Query', async () => { - const query = 'SELECT AVG(age) FROM student'; - const result = await executeSELECTQuery(query); - // Assuming AVG returns a single decimal point value - expect(result).toEqual([{ 'AVG(age)': 25.25 }]); -}); - -test('Execute MIN Aggregate Query', async () => { - const query = 'SELECT MIN(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MIN(age)': 22 }]); -}); - -test('Execute MAX Aggregate Query', async () => { - const query = 'SELECT MAX(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MAX(age)': 30 }]); -}); - -test('Count students per age', async () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '22', 'COUNT(*)': 1 }, - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments per course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 }, - { course: 'Physics', 'COUNT(*)': 1 }, - { course: 'Chemistry', 'COUNT(*)': 1 }, - { course: 'Biology', 'COUNT(*)': 1 } - ]); -}); - - -test('Count courses per student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 }, - { student_id: '2', 'COUNT(*)': 1 }, - { student_id: '3', 'COUNT(*)': 1 }, - { student_id: '5', 'COUNT(*)': 1 } - ]); -}); - -test('Count students within a specific age range', async () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments for a specific course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 } - ]); -}); - -test('Count courses for a specific student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 } - ]); -}); - -test('Average age of students above a certain age', async () => { - const query = 'SELECT AVG(age) FROM student WHERE age > 22'; - const result = await executeSELECTQuery(query); - const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 - expect(result).toEqual([{ 'AVG(age)': expectedAverage }]); -}); - -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", }) -}); - -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}); - -test('Parse INNER JOIN clause', () => { - const query = 'SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'INNER', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' }, - }); -}); - -test('Parse LEFT JOIN clause', () => { - const query = 'SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'LEFT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Parse RIGHT JOIN clause', () => { - const query = 'SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'RIGHT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Returns null for queries without JOIN', () => { - const query = 'SELECT * FROM table1'; - const result = parseJoinClause(query); - expect(result).toEqual( - { - joinType: null, - joinTable: null, - joinCondition: null - } - ); -}); - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'LEFT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'RIGHT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse COUNT Aggregate Query', () => { - const query = 'SELECT COUNT(*) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse SUM Aggregate Query', () => { - const query = 'SELECT SUM(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['SUM(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse AVG Aggregate Query', () => { - const query = 'SELECT AVG(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['AVG(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MIN Aggregate Query', () => { - const query = 'SELECT MIN(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MIN(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MAX Aggregate Query', () => { - const query = 'SELECT MAX(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MAX(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse basic GROUP BY query', () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with WHERE clause', () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'age', operator: '>', value: '22' }], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with multiple fields', () => { - const query = 'SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student_id', 'course', 'COUNT(*)'], - table: 'enrollment', - whereClauses: [], - groupByFields: ['student_id', 'course'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with JOIN and WHERE clauses', () => { - const query = 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student.name', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'enrollment.course', operator: '=', value: '"Mathematics"' }], - groupByFields: ['student.name'], - joinType: 'INNER', - joinTable: 'enrollment', - joinCondition: { - left: 'student.id', - right: 'enrollment.student_id' - }, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false, - }); -}); - -test('Execute SQL Query with ORDER BY', async () => { - const query = 'SELECT name FROM student ORDER BY name ASC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Jane' }, - { name: 'John' } - ]); -}); - -test('Execute SQL Query with ORDER BY and WHERE', async () => { - const query = 'SELECT name FROM student WHERE age > 24 ORDER BY name DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'John' }, - { name: 'Jane' }, - ]); -}); -test('Execute SQL Query with ORDER BY and GROUP BY', async () => { - const query = 'SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { age: '30', 'COUNT(id) as count': 1 }, - { age: '25', 'COUNT(id) as count': 1 }, - { age: '24', 'COUNT(id) as count': 1 }, - { age: '22', 'COUNT(id) as count': 1 } - ]); -}); - -test('Execute SQL Query with standard LIMIT clause', async () => { - const query = 'SELECT id, name FROM student LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with LIMIT clause equal to total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 4'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LIMIT clause exceeding total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 10'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); // Total rows in student.csv -}); - -test('Execute SQL Query with LIMIT 0', async () => { - const query = 'SELECT id, name FROM student LIMIT 0'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(0); -}); - -test('Execute SQL Query with LIMIT and ORDER BY clause', async () => { - const query = 'SELECT id, name FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); - expect(result[0].name).toEqual('John'); - expect(result[1].name).toEqual('Jane'); -}); - -test('Error Handling with Malformed Query', async () => { - const query = 'SELECT FROM table'; // intentionally malformed - await expect(executeSELECTQuery(query)).rejects.toThrow("Error executing query: Query parsing error: Invalid SELECT format"); -}); - -test('Basic DISTINCT Usage', async () => { - const query = 'SELECT DISTINCT age FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ age: '30' }, { age: '25' }, { age: '22' }, { age: '24' }]); -}); - -test('DISTINCT with Multiple Columns', async () => { - const query = 'SELECT DISTINCT student_id, course FROM enrollment'; - const result = await executeSELECTQuery(query); - // Expecting unique combinations of student_id and course - expect(result).toEqual([ - { student_id: '1', course: 'Mathematics' }, - { student_id: '1', course: 'Physics' }, - { student_id: '2', course: 'Chemistry' }, - { student_id: '3', course: 'Mathematics' }, - { student_id: '5', course: 'Biology' }, - ]); + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": null, + "enrollment.course": "Biology", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "enrollment.course": "Physics", + "student.name": "John", + }), + ]) + ); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Physics", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); + +test("Execute COUNT Aggregate Query", async () => { + const query = "SELECT COUNT(*) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "COUNT(*)": 4 }]); +}); + +test("Execute SUM Aggregate Query", async () => { + const query = "SELECT SUM(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "SUM(age)": 101 }]); +}); + +test("Execute AVG Aggregate Query", async () => { + const query = "SELECT AVG(age) FROM student"; + const result = await executeSELECTQuery(query); + // Assuming AVG returns a single decimal point value + expect(result).toEqual([{ "AVG(age)": 25.25 }]); +}); + +test("Execute MIN Aggregate Query", async () => { + const query = "SELECT MIN(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MIN(age)": 22 }]); +}); + +test("Execute MAX Aggregate Query", async () => { + const query = "SELECT MAX(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MAX(age)": 30 }]); +}); + +test("Count students per age", async () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "22", "COUNT(*)": 1 }, + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments per course", async () => { + const query = "SELECT course, COUNT(*) FROM enrollment GROUP BY course"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { course: "Mathematics", "COUNT(*)": 2 }, + { course: "Physics", "COUNT(*)": 1 }, + { course: "Chemistry", "COUNT(*)": 1 }, + { course: "Biology", "COUNT(*)": 1 }, + ]); +}); + +test("Count courses per student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { student_id: "1", "COUNT(*)": 2 }, + { student_id: "2", "COUNT(*)": 1 }, + { student_id: "3", "COUNT(*)": 1 }, + { student_id: "5", "COUNT(*)": 1 }, + ]); +}); + +test("Count students within a specific age range", async () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments for a specific course", async () => { + const query = + 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ course: "Mathematics", "COUNT(*)": 2 }]); +}); + +test("Count courses for a specific student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ student_id: "1", "COUNT(*)": 2 }]); +}); + +test("Average age of students above a certain age", async () => { + const query = "SELECT AVG(age) FROM student WHERE age > 22"; + const result = await executeSELECTQuery(query); + const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 + expect(result).toEqual([{ "AVG(age)": expectedAverage }]); +}); + +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse INNER JOIN clause", () => { + const query = + "SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "INNER", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse LEFT JOIN clause", () => { + const query = + "SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "LEFT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse RIGHT JOIN clause", () => { + const query = + "SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "RIGHT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Returns null for queries without JOIN", () => { + const query = "SELECT * FROM table1"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: null, + joinTable: null, + joinCondition: null, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "LEFT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "RIGHT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "22" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Physics'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [{ field: "student.age", operator: "<", value: "25" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Chemistry'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse COUNT Aggregate Query", () => { + const query = "SELECT COUNT(*) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SUM Aggregate Query", () => { + const query = "SELECT SUM(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["SUM(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse AVG Aggregate Query", () => { + const query = "SELECT AVG(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["AVG(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MIN Aggregate Query", () => { + const query = "SELECT MIN(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MIN(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MAX Aggregate Query", () => { + const query = "SELECT MAX(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MAX(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse basic GROUP BY query", () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with WHERE clause", () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [{ field: "age", operator: ">", value: "22" }], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with multiple fields", () => { + const query = + "SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course", "COUNT(*)"], + table: "enrollment", + whereClauses: [], + groupByFields: ["student_id", "course"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with JOIN and WHERE clauses", () => { + const query = + 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name", "COUNT(*)"], + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: '"Mathematics"' }, + ], + groupByFields: ["student.name"], + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query with ORDER BY", async () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { name: "Alice" }, + { name: "Bob" }, + { name: "Jane" }, + { name: "John" }, + ]); +}); + +test("Execute SQL Query with ORDER BY and WHERE", async () => { + const query = "SELECT name FROM student WHERE age > 24 ORDER BY name DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([{ name: "John" }, { name: "Jane" }]); +}); +test("Execute SQL Query with ORDER BY and GROUP BY", async () => { + const query = + "SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { age: "30", "COUNT(id) as count": 1 }, + { age: "25", "COUNT(id) as count": 1 }, + { age: "24", "COUNT(id) as count": 1 }, + { age: "22", "COUNT(id) as count": 1 }, + ]); +}); + +test("Execute SQL Query with standard LIMIT clause", async () => { + const query = "SELECT id, name FROM student LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with LIMIT clause equal to total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 4"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LIMIT clause exceeding total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 10"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); // Total rows in student.csv +}); + +test("Execute SQL Query with LIMIT 0", async () => { + const query = "SELECT id, name FROM student LIMIT 0"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(0); +}); + +test("Execute SQL Query with LIMIT and ORDER BY clause", async () => { + const query = "SELECT id, name FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); + expect(result[0].name).toEqual("John"); + expect(result[1].name).toEqual("Jane"); +}); + +test("Error Handling with Malformed Query", async () => { + const query = "SELECT FROM table"; // intentionally malformed + await expect(executeSELECTQuery(query)).rejects.toThrow( + "Error executing query: Query parsing error: Invalid SELECT format" + ); +}); + +test("Basic DISTINCT Usage", async () => { + const query = "SELECT DISTINCT age FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "30" }, + { age: "25" }, + { age: "22" }, + { age: "24" }, + ]); +}); + +test("DISTINCT with Multiple Columns", async () => { + const query = "SELECT DISTINCT student_id, course FROM enrollment"; + const result = await executeSELECTQuery(query); + // Expecting unique combinations of student_id and course + expect(result).toEqual([ + { student_id: "1", course: "Mathematics" }, + { student_id: "1", course: "Physics" }, + { student_id: "2", course: "Chemistry" }, + { student_id: "3", course: "Mathematics" }, + { student_id: "5", course: "Biology" }, + ]); }); // Not a good test right now -test('DISTINCT with WHERE Clause', async () => { - const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; - const result = await executeSELECTQuery(query); - // Expecting courses taken by student with ID 1 - expect(result).toEqual([{ course: 'Mathematics' }, { course: 'Physics' }]); -}); - -test('DISTINCT with JOIN Operations', async () => { - const query = 'SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id'; - const result = await executeSELECTQuery(query); - // Expecting names of students who are enrolled in any course - expect(result).toEqual([{ "student.name": 'John' }, { "student.name": 'Jane' }, { "student.name": 'Bob' }]); -}); - -test('DISTINCT with ORDER BY and LIMIT', async () => { - const query = 'SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - // Expecting the two highest unique ages - expect(result).toEqual([{ age: '30' }, { age: '25' }]); -}); \ No newline at end of file +test("DISTINCT with WHERE Clause", async () => { + const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; + const result = await executeSELECTQuery(query); + // Expecting courses taken by student with ID 1 + expect(result).toEqual([{ course: "Mathematics" }, { course: "Physics" }]); +}); + +test("DISTINCT with JOIN Operations", async () => { + const query = + "SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id"; + const result = await executeSELECTQuery(query); + // Expecting names of students who are enrolled in any course + expect(result).toEqual([ + { "student.name": "John" }, + { "student.name": "Jane" }, + { "student.name": "Bob" }, + ]); +}); + +test("DISTINCT with ORDER BY and LIMIT", async () => { + const query = "SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the two highest unique ages + expect(result).toEqual([{ age: "30" }, { age: "25" }]); +}); diff --git a/tests/step-15/index.test.js b/tests/step-15/index.test.js index a2aa4daee..7847e800c 100644 --- a/tests/step-15/index.test.js +++ b/tests/step-15/index.test.js @@ -1,59 +1,60 @@ -const readCSV = require('../../src/csvReader'); -const {parseQuery, parseJoinClause} = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); - -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(4); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); - -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); - -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('id'); -}); - -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('name'); -}); - -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -61,18 +62,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -86,737 +90,888 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); - -test('Execute SQL Query with RIGHT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": null, "enrollment.course": "Biology" }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "John" }), - expect.objectContaining({ "enrollment.course": "Physics", "student.name": "John" }) - ])); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "John", "enrollment.course": "Physics" }) - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "Bob" }), - expect.objectContaining({ "enrollment.course": "Biology", "student.name": null }) - ])); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Chemistry", "student.name": "Jane" }), - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; - const result = await executeSELECTQuery(query); - expect(result).toEqual([]); -}); - -test('Execute COUNT Aggregate Query', async () => { - const query = 'SELECT COUNT(*) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'COUNT(*)': 4 }]); -}); - -test('Execute SUM Aggregate Query', async () => { - const query = 'SELECT SUM(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'SUM(age)': 101 }]); -}); - -test('Execute AVG Aggregate Query', async () => { - const query = 'SELECT AVG(age) FROM student'; - const result = await executeSELECTQuery(query); - // Assuming AVG returns a single decimal point value - expect(result).toEqual([{ 'AVG(age)': 25.25 }]); -}); - -test('Execute MIN Aggregate Query', async () => { - const query = 'SELECT MIN(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MIN(age)': 22 }]); -}); - -test('Execute MAX Aggregate Query', async () => { - const query = 'SELECT MAX(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MAX(age)': 30 }]); -}); - -test('Count students per age', async () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '22', 'COUNT(*)': 1 }, - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments per course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 }, - { course: 'Physics', 'COUNT(*)': 1 }, - { course: 'Chemistry', 'COUNT(*)': 1 }, - { course: 'Biology', 'COUNT(*)': 1 } - ]); -}); - - -test('Count courses per student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 }, - { student_id: '2', 'COUNT(*)': 1 }, - { student_id: '3', 'COUNT(*)': 1 }, - { student_id: '5', 'COUNT(*)': 1 } - ]); -}); - -test('Count students within a specific age range', async () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments for a specific course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 } - ]); -}); - -test('Count courses for a specific student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 } - ]); -}); - -test('Average age of students above a certain age', async () => { - const query = 'SELECT AVG(age) FROM student WHERE age > 22'; - const result = await executeSELECTQuery(query); - const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 - expect(result).toEqual([{ 'AVG(age)': expectedAverage }]); -}); - -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}); - -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", }) -}); - -test('Parse INNER JOIN clause', () => { - const query = 'SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'INNER', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' }, - }); -}); - -test('Parse LEFT JOIN clause', () => { - const query = 'SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'LEFT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Parse RIGHT JOIN clause', () => { - const query = 'SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'RIGHT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Returns null for queries without JOIN', () => { - const query = 'SELECT * FROM table1'; - const result = parseJoinClause(query); - expect(result).toEqual( - { - joinType: null, - joinTable: null, - joinCondition: null - } - ); -}); - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'LEFT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'RIGHT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse COUNT Aggregate Query', () => { - const query = 'SELECT COUNT(*) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse SUM Aggregate Query', () => { - const query = 'SELECT SUM(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['SUM(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse AVG Aggregate Query', () => { - const query = 'SELECT AVG(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['AVG(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MIN Aggregate Query', () => { - const query = 'SELECT MIN(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MIN(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MAX Aggregate Query', () => { - const query = 'SELECT MAX(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MAX(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse basic GROUP BY query', () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with WHERE clause', () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'age', operator: '>', value: '22' }], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with multiple fields', () => { - const query = 'SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student_id', 'course', 'COUNT(*)'], - table: 'enrollment', - whereClauses: [], - groupByFields: ['student_id', 'course'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with JOIN and WHERE clauses', () => { - const query = 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student.name', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'enrollment.course', operator: '=', value: '"Mathematics"' }], - groupByFields: ['student.name'], - joinType: 'INNER', - joinTable: 'enrollment', - joinCondition: { - left: 'student.id', - right: 'enrollment.student_id' - }, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false, - }); -}); - -test('Execute SQL Query with ORDER BY', async () => { - const query = 'SELECT name FROM student ORDER BY name ASC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Jane' }, - { name: 'John' } - ]); -}); - -test('Execute SQL Query with ORDER BY and WHERE', async () => { - const query = 'SELECT name FROM student WHERE age > 24 ORDER BY name DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'John' }, - { name: 'Jane' }, - ]); -}); -test('Execute SQL Query with ORDER BY and GROUP BY', async () => { - const query = 'SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { age: '30', 'COUNT(id) as count': 1 }, - { age: '25', 'COUNT(id) as count': 1 }, - { age: '24', 'COUNT(id) as count': 1 }, - { age: '22', 'COUNT(id) as count': 1 } - ]); -}); - -test('Execute SQL Query with standard LIMIT clause', async () => { - const query = 'SELECT id, name FROM student LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with LIMIT clause equal to total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 4'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LIMIT clause exceeding total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 10'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); // Total rows in student.csv -}); - -test('Execute SQL Query with LIMIT 0', async () => { - const query = 'SELECT id, name FROM student LIMIT 0'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(0); -}); - -test('Execute SQL Query with LIMIT and ORDER BY clause', async () => { - const query = 'SELECT id, name FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); - expect(result[0].name).toEqual('John'); - expect(result[1].name).toEqual('Jane'); -}); - -test('Error Handling with Malformed Query', async () => { - const query = 'SELECT FROM table'; // intentionally malformed - await expect(executeSELECTQuery(query)).rejects.toThrow("Error executing query: Query parsing error: Invalid SELECT format"); -}); - -test('Basic DISTINCT Usage', async () => { - const query = 'SELECT DISTINCT age FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ age: '30' }, { age: '25' }, { age: '22' }, { age: '24' }]); -}); - -test('DISTINCT with Multiple Columns', async () => { - const query = 'SELECT DISTINCT student_id, course FROM enrollment'; - const result = await executeSELECTQuery(query); - // Expecting unique combinations of student_id and course - expect(result).toEqual([ - { student_id: '1', course: 'Mathematics' }, - { student_id: '1', course: 'Physics' }, - { student_id: '2', course: 'Chemistry' }, - { student_id: '3', course: 'Mathematics' }, - { student_id: '5', course: 'Biology' }, - ]); + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": null, + "enrollment.course": "Biology", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "enrollment.course": "Physics", + "student.name": "John", + }), + ]) + ); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Physics", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); + +test("Execute COUNT Aggregate Query", async () => { + const query = "SELECT COUNT(*) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "COUNT(*)": 4 }]); +}); + +test("Execute SUM Aggregate Query", async () => { + const query = "SELECT SUM(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "SUM(age)": 101 }]); +}); + +test("Execute AVG Aggregate Query", async () => { + const query = "SELECT AVG(age) FROM student"; + const result = await executeSELECTQuery(query); + // Assuming AVG returns a single decimal point value + expect(result).toEqual([{ "AVG(age)": 25.25 }]); +}); + +test("Execute MIN Aggregate Query", async () => { + const query = "SELECT MIN(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MIN(age)": 22 }]); +}); + +test("Execute MAX Aggregate Query", async () => { + const query = "SELECT MAX(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MAX(age)": 30 }]); +}); + +test("Count students per age", async () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "22", "COUNT(*)": 1 }, + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments per course", async () => { + const query = "SELECT course, COUNT(*) FROM enrollment GROUP BY course"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { course: "Mathematics", "COUNT(*)": 2 }, + { course: "Physics", "COUNT(*)": 1 }, + { course: "Chemistry", "COUNT(*)": 1 }, + { course: "Biology", "COUNT(*)": 1 }, + ]); +}); + +test("Count courses per student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { student_id: "1", "COUNT(*)": 2 }, + { student_id: "2", "COUNT(*)": 1 }, + { student_id: "3", "COUNT(*)": 1 }, + { student_id: "5", "COUNT(*)": 1 }, + ]); +}); + +test("Count students within a specific age range", async () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments for a specific course", async () => { + const query = + 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ course: "Mathematics", "COUNT(*)": 2 }]); +}); + +test("Count courses for a specific student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ student_id: "1", "COUNT(*)": 2 }]); +}); + +test("Average age of students above a certain age", async () => { + const query = "SELECT AVG(age) FROM student WHERE age > 22"; + const result = await executeSELECTQuery(query); + const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 + expect(result).toEqual([{ "AVG(age)": expectedAverage }]); +}); + +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse INNER JOIN clause", () => { + const query = + "SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "INNER", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse LEFT JOIN clause", () => { + const query = + "SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "LEFT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse RIGHT JOIN clause", () => { + const query = + "SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "RIGHT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Returns null for queries without JOIN", () => { + const query = "SELECT * FROM table1"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: null, + joinTable: null, + joinCondition: null, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "LEFT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "RIGHT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "22" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Physics'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [{ field: "student.age", operator: "<", value: "25" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Chemistry'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse COUNT Aggregate Query", () => { + const query = "SELECT COUNT(*) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SUM Aggregate Query", () => { + const query = "SELECT SUM(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["SUM(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse AVG Aggregate Query", () => { + const query = "SELECT AVG(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["AVG(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MIN Aggregate Query", () => { + const query = "SELECT MIN(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MIN(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MAX Aggregate Query", () => { + const query = "SELECT MAX(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MAX(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse basic GROUP BY query", () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with WHERE clause", () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [{ field: "age", operator: ">", value: "22" }], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with multiple fields", () => { + const query = + "SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course", "COUNT(*)"], + table: "enrollment", + whereClauses: [], + groupByFields: ["student_id", "course"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with JOIN and WHERE clauses", () => { + const query = + 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name", "COUNT(*)"], + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: '"Mathematics"' }, + ], + groupByFields: ["student.name"], + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query with ORDER BY", async () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { name: "Alice" }, + { name: "Bob" }, + { name: "Jane" }, + { name: "John" }, + ]); +}); + +test("Execute SQL Query with ORDER BY and WHERE", async () => { + const query = "SELECT name FROM student WHERE age > 24 ORDER BY name DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([{ name: "John" }, { name: "Jane" }]); +}); +test("Execute SQL Query with ORDER BY and GROUP BY", async () => { + const query = + "SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { age: "30", "COUNT(id) as count": 1 }, + { age: "25", "COUNT(id) as count": 1 }, + { age: "24", "COUNT(id) as count": 1 }, + { age: "22", "COUNT(id) as count": 1 }, + ]); +}); + +test("Execute SQL Query with standard LIMIT clause", async () => { + const query = "SELECT id, name FROM student LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with LIMIT clause equal to total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 4"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LIMIT clause exceeding total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 10"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); // Total rows in student.csv +}); + +test("Execute SQL Query with LIMIT 0", async () => { + const query = "SELECT id, name FROM student LIMIT 0"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(0); +}); + +test("Execute SQL Query with LIMIT and ORDER BY clause", async () => { + const query = "SELECT id, name FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); + expect(result[0].name).toEqual("John"); + expect(result[1].name).toEqual("Jane"); +}); + +test("Error Handling with Malformed Query", async () => { + const query = "SELECT FROM table"; // intentionally malformed + await expect(executeSELECTQuery(query)).rejects.toThrow( + "Error executing query: Query parsing error: Invalid SELECT format" + ); +}); + +test("Basic DISTINCT Usage", async () => { + const query = "SELECT DISTINCT age FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "30" }, + { age: "25" }, + { age: "22" }, + { age: "24" }, + ]); +}); + +test("DISTINCT with Multiple Columns", async () => { + const query = "SELECT DISTINCT student_id, course FROM enrollment"; + const result = await executeSELECTQuery(query); + // Expecting unique combinations of student_id and course + expect(result).toEqual([ + { student_id: "1", course: "Mathematics" }, + { student_id: "1", course: "Physics" }, + { student_id: "2", course: "Chemistry" }, + { student_id: "3", course: "Mathematics" }, + { student_id: "5", course: "Biology" }, + ]); }); // Not a good test right now -test('DISTINCT with WHERE Clause', async () => { - const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; - const result = await executeSELECTQuery(query); - // Expecting courses taken by student with ID 1 - expect(result).toEqual([{ course: 'Mathematics' }, { course: 'Physics' }]); -}); - -test('DISTINCT with JOIN Operations', async () => { - const query = 'SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id'; - const result = await executeSELECTQuery(query); - // Expecting names of students who are enrolled in any course - expect(result).toEqual([{ "student.name": 'John' }, { "student.name": 'Jane' }, { "student.name": 'Bob' }]); +test("DISTINCT with WHERE Clause", async () => { + const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; + const result = await executeSELECTQuery(query); + // Expecting courses taken by student with ID 1 + expect(result).toEqual([{ course: "Mathematics" }, { course: "Physics" }]); +}); + +test("DISTINCT with JOIN Operations", async () => { + const query = + "SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id"; + const result = await executeSELECTQuery(query); + // Expecting names of students who are enrolled in any course + expect(result).toEqual([ + { "student.name": "John" }, + { "student.name": "Jane" }, + { "student.name": "Bob" }, + ]); +}); + +test("DISTINCT with ORDER BY and LIMIT", async () => { + const query = "SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the two highest unique ages + expect(result).toEqual([{ age: "30" }, { age: "25" }]); +}); + +test("Execute SQL Query with LIKE Operator for Name", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; + const result = await executeSELECTQuery(query); + // Expecting names containing 'Jane' + expect(result).toEqual([{ name: "Jane" }]); +}); + +test("Execute SQL Query with LIKE Operator and Wildcards", async () => { + const query = "SELECT name FROM student WHERE name LIKE 'J%'"; + const result = await executeSELECTQuery(query); + // Expecting names starting with 'J' + expect(result).toEqual([{ name: "John" }, { name: "Jane" }]); +}); + +test("Execute SQL Query with LIKE Operator Case Insensitive", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%bob%'"; + const result = await executeSELECTQuery(query); + // Expecting names 'Bob' (case insensitive) + expect(result).toEqual([{ name: "Bob" }]); +}); + +test("Execute SQL Query with LIKE Operator and DISTINCT", async () => { + const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%'"; + const result = await executeSELECTQuery(query); + // Expecting unique names containing 'e' + expect(result).toEqual([{ name: "Jane" }, { name: "Alice" }]); +}); + +test("LIKE with ORDER BY and LIMIT", async () => { + const query = + "SELECT name FROM student WHERE name LIKE '%a%' ORDER BY name ASC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the first two names alphabetically that contain 'a' + expect(result).toEqual([{ name: "Alice" }, { name: "Jane" }]); +}); +test("Parse SQL Query with LIKE Clause", () => { + const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["name"], + table: "student", + whereClauses: [{ field: "name", operator: "LIKE", value: "%Jane%" }], + isDistinct: false, + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with LIKE Clause and Wildcards", () => { + const query = "SELECT name FROM student WHERE name LIKE 'J%'"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["name"], + table: "student", + whereClauses: [{ field: "name", operator: "LIKE", value: "J%" }], + isDistinct: false, + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with Multiple LIKE Clauses", () => { + const query = + "SELECT name FROM student WHERE name LIKE 'J%' AND age LIKE '2%'"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["name"], + table: "student", + whereClauses: [ + { field: "name", operator: "LIKE", value: "J%" }, + { field: "age", operator: "LIKE", value: "2%" }, + ], + isDistinct: false, + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + orderByFields: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); +}); + +test("Parse SQL Query with LIKE and ORDER BY Clauses", () => { + const query = + "SELECT name FROM student WHERE name LIKE '%e%' ORDER BY age DESC"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["name"], + table: "student", + whereClauses: [{ field: "name", operator: "LIKE", value: "%e%" }], + orderByFields: [{ fieldName: "age", order: "DESC" }], + isDistinct: false, + groupByFields: null, + joinType: null, + joinTable: null, + joinCondition: null, + limit: null, + hasAggregateWithoutGroupBy: false, + }); }); - -test('DISTINCT with ORDER BY and LIMIT', async () => { - const query = 'SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - // Expecting the two highest unique ages - expect(result).toEqual([{ age: '30' }, { age: '25' }]); -}); - -test('Execute SQL Query with LIKE Operator for Name', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; - const result = await executeSELECTQuery(query); - // Expecting names containing 'Jane' - expect(result).toEqual([{ name: 'Jane' }]); -}); - -test('Execute SQL Query with LIKE Operator and Wildcards', async () => { - const query = "SELECT name FROM student WHERE name LIKE 'J%'"; - const result = await executeSELECTQuery(query); - // Expecting names starting with 'J' - expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); -}); - -test('Execute SQL Query with LIKE Operator Case Insensitive', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%bob%'"; - const result = await executeSELECTQuery(query); - // Expecting names 'Bob' (case insensitive) - expect(result).toEqual([{ name: 'Bob' }]); -}); - -test('Execute SQL Query with LIKE Operator and DISTINCT', async () => { - const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%'"; - const result = await executeSELECTQuery(query); - // Expecting unique names containing 'e' - expect(result).toEqual([{ name: 'Jane' }, { name: 'Alice' }]); -}); - -test('LIKE with ORDER BY and LIMIT', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%a%' ORDER BY name ASC LIMIT 2"; - const result = await executeSELECTQuery(query); - // Expecting the first two names alphabetically that contain 'a' - expect(result).toEqual([{ name: 'Alice' }, { name: 'Jane' }]); -}); \ No newline at end of file diff --git a/tests/step-16/index.test.js b/tests/step-16/index.test.js index a2aa4daee..649bde067 100644 --- a/tests/step-16/index.test.js +++ b/tests/step-16/index.test.js @@ -1,59 +1,60 @@ -const readCSV = require('../../src/csvReader'); -const {parseQuery, parseJoinClause} = require('../../src/queryParser'); -const executeSELECTQuery = require('../../src/index'); - -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(4); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); - -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); - -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('id'); -}); - -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('name'); -}); - -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +const { readCSV } = require("../../src/csvReader"); +const { parseSelectQuery, parseJoinClause } = require("../../src/queryParser"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -61,18 +62,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -86,737 +90,812 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); - -test('Execute SQL Query with RIGHT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": null, "enrollment.course": "Biology" }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "John" }), - expect.objectContaining({ "enrollment.course": "Physics", "student.name": "John" }) - ])); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "John", "enrollment.course": "Physics" }) - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "Bob" }), - expect.objectContaining({ "enrollment.course": "Biology", "student.name": null }) - ])); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Chemistry", "student.name": "Jane" }), - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; - const result = await executeSELECTQuery(query); - expect(result).toEqual([]); -}); - -test('Execute COUNT Aggregate Query', async () => { - const query = 'SELECT COUNT(*) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'COUNT(*)': 4 }]); -}); - -test('Execute SUM Aggregate Query', async () => { - const query = 'SELECT SUM(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'SUM(age)': 101 }]); -}); - -test('Execute AVG Aggregate Query', async () => { - const query = 'SELECT AVG(age) FROM student'; - const result = await executeSELECTQuery(query); - // Assuming AVG returns a single decimal point value - expect(result).toEqual([{ 'AVG(age)': 25.25 }]); -}); - -test('Execute MIN Aggregate Query', async () => { - const query = 'SELECT MIN(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MIN(age)': 22 }]); -}); - -test('Execute MAX Aggregate Query', async () => { - const query = 'SELECT MAX(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MAX(age)': 30 }]); -}); - -test('Count students per age', async () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '22', 'COUNT(*)': 1 }, - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments per course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 }, - { course: 'Physics', 'COUNT(*)': 1 }, - { course: 'Chemistry', 'COUNT(*)': 1 }, - { course: 'Biology', 'COUNT(*)': 1 } - ]); -}); - - -test('Count courses per student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 }, - { student_id: '2', 'COUNT(*)': 1 }, - { student_id: '3', 'COUNT(*)': 1 }, - { student_id: '5', 'COUNT(*)': 1 } - ]); -}); - -test('Count students within a specific age range', async () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments for a specific course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 } - ]); -}); - -test('Count courses for a specific student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 } - ]); -}); - -test('Average age of students above a certain age', async () => { - const query = 'SELECT AVG(age) FROM student WHERE age > 22'; - const result = await executeSELECTQuery(query); - const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 - expect(result).toEqual([{ 'AVG(age)': expectedAverage }]); -}); - -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", }) -}); - -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}); - -test('Parse INNER JOIN clause', () => { - const query = 'SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'INNER', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' }, - }); -}); - -test('Parse LEFT JOIN clause', () => { - const query = 'SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'LEFT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Parse RIGHT JOIN clause', () => { - const query = 'SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'RIGHT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Returns null for queries without JOIN', () => { - const query = 'SELECT * FROM table1'; - const result = parseJoinClause(query); - expect(result).toEqual( - { - joinType: null, - joinTable: null, - joinCondition: null - } - ); -}); - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'LEFT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'RIGHT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await parseQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse COUNT Aggregate Query', () => { - const query = 'SELECT COUNT(*) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse SUM Aggregate Query', () => { - const query = 'SELECT SUM(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['SUM(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse AVG Aggregate Query', () => { - const query = 'SELECT AVG(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['AVG(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MIN Aggregate Query', () => { - const query = 'SELECT MIN(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MIN(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MAX Aggregate Query', () => { - const query = 'SELECT MAX(age) FROM student'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['MAX(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse basic GROUP BY query', () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with WHERE clause', () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'age', operator: '>', value: '22' }], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with multiple fields', () => { - const query = 'SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student_id', 'course', 'COUNT(*)'], - table: 'enrollment', - whereClauses: [], - groupByFields: ['student_id', 'course'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with JOIN and WHERE clauses', () => { - const query = 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; - const parsed = parseQuery(query); - expect(parsed).toEqual({ - fields: ['student.name', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'enrollment.course', operator: '=', value: '"Mathematics"' }], - groupByFields: ['student.name'], - joinType: 'INNER', - joinTable: 'enrollment', - joinCondition: { - left: 'student.id', - right: 'enrollment.student_id' - }, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false, - }); -}); - -test('Execute SQL Query with ORDER BY', async () => { - const query = 'SELECT name FROM student ORDER BY name ASC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Jane' }, - { name: 'John' } - ]); -}); - -test('Execute SQL Query with ORDER BY and WHERE', async () => { - const query = 'SELECT name FROM student WHERE age > 24 ORDER BY name DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'John' }, - { name: 'Jane' }, - ]); -}); -test('Execute SQL Query with ORDER BY and GROUP BY', async () => { - const query = 'SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { age: '30', 'COUNT(id) as count': 1 }, - { age: '25', 'COUNT(id) as count': 1 }, - { age: '24', 'COUNT(id) as count': 1 }, - { age: '22', 'COUNT(id) as count': 1 } - ]); -}); - -test('Execute SQL Query with standard LIMIT clause', async () => { - const query = 'SELECT id, name FROM student LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with LIMIT clause equal to total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 4'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LIMIT clause exceeding total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 10'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); // Total rows in student.csv -}); - -test('Execute SQL Query with LIMIT 0', async () => { - const query = 'SELECT id, name FROM student LIMIT 0'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(0); -}); - -test('Execute SQL Query with LIMIT and ORDER BY clause', async () => { - const query = 'SELECT id, name FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); - expect(result[0].name).toEqual('John'); - expect(result[1].name).toEqual('Jane'); -}); - -test('Error Handling with Malformed Query', async () => { - const query = 'SELECT FROM table'; // intentionally malformed - await expect(executeSELECTQuery(query)).rejects.toThrow("Error executing query: Query parsing error: Invalid SELECT format"); -}); - -test('Basic DISTINCT Usage', async () => { - const query = 'SELECT DISTINCT age FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ age: '30' }, { age: '25' }, { age: '22' }, { age: '24' }]); -}); - -test('DISTINCT with Multiple Columns', async () => { - const query = 'SELECT DISTINCT student_id, course FROM enrollment'; - const result = await executeSELECTQuery(query); - // Expecting unique combinations of student_id and course - expect(result).toEqual([ - { student_id: '1', course: 'Mathematics' }, - { student_id: '1', course: 'Physics' }, - { student_id: '2', course: 'Chemistry' }, - { student_id: '3', course: 'Mathematics' }, - { student_id: '5', course: 'Biology' }, - ]); + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": null, + "enrollment.course": "Biology", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "enrollment.course": "Physics", + "student.name": "John", + }), + ]) + ); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Physics", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); + +test("Execute COUNT Aggregate Query", async () => { + const query = "SELECT COUNT(*) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "COUNT(*)": 4 }]); +}); + +test("Execute SUM Aggregate Query", async () => { + const query = "SELECT SUM(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "SUM(age)": 101 }]); +}); + +test("Execute AVG Aggregate Query", async () => { + const query = "SELECT AVG(age) FROM student"; + const result = await executeSELECTQuery(query); + // Assuming AVG returns a single decimal point value + expect(result).toEqual([{ "AVG(age)": 25.25 }]); +}); + +test("Execute MIN Aggregate Query", async () => { + const query = "SELECT MIN(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MIN(age)": 22 }]); +}); + +test("Execute MAX Aggregate Query", async () => { + const query = "SELECT MAX(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MAX(age)": 30 }]); +}); + +test("Count students per age", async () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "22", "COUNT(*)": 1 }, + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments per course", async () => { + const query = "SELECT course, COUNT(*) FROM enrollment GROUP BY course"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { course: "Mathematics", "COUNT(*)": 2 }, + { course: "Physics", "COUNT(*)": 1 }, + { course: "Chemistry", "COUNT(*)": 1 }, + { course: "Biology", "COUNT(*)": 1 }, + ]); +}); + +test("Count courses per student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { student_id: "1", "COUNT(*)": 2 }, + { student_id: "2", "COUNT(*)": 1 }, + { student_id: "3", "COUNT(*)": 1 }, + { student_id: "5", "COUNT(*)": 1 }, + ]); +}); + +test("Count students within a specific age range", async () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments for a specific course", async () => { + const query = + 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ course: "Mathematics", "COUNT(*)": 2 }]); +}); + +test("Count courses for a specific student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ student_id: "1", "COUNT(*)": 2 }]); +}); + +test("Average age of students above a certain age", async () => { + const query = "SELECT AVG(age) FROM student WHERE age > 22"; + const result = await executeSELECTQuery(query); + const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 + expect(result).toEqual([{ "AVG(age)": expectedAverage }]); +}); + +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse INNER JOIN clause", () => { + const query = + "SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "INNER", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse LEFT JOIN clause", () => { + const query = + "SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "LEFT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse RIGHT JOIN clause", () => { + const query = + "SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "RIGHT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Returns null for queries without JOIN", () => { + const query = "SELECT * FROM table1"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: null, + joinTable: null, + joinCondition: null, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "LEFT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "RIGHT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "22" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Physics'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [{ field: "student.age", operator: "<", value: "25" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Chemistry'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse COUNT Aggregate Query", () => { + const query = "SELECT COUNT(*) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SUM Aggregate Query", () => { + const query = "SELECT SUM(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["SUM(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse AVG Aggregate Query", () => { + const query = "SELECT AVG(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["AVG(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MIN Aggregate Query", () => { + const query = "SELECT MIN(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MIN(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MAX Aggregate Query", () => { + const query = "SELECT MAX(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MAX(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse basic GROUP BY query", () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with WHERE clause", () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [{ field: "age", operator: ">", value: "22" }], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with multiple fields", () => { + const query = + "SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course", "COUNT(*)"], + table: "enrollment", + whereClauses: [], + groupByFields: ["student_id", "course"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with JOIN and WHERE clauses", () => { + const query = + 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name", "COUNT(*)"], + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: '"Mathematics"' }, + ], + groupByFields: ["student.name"], + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query with ORDER BY", async () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { name: "Alice" }, + { name: "Bob" }, + { name: "Jane" }, + { name: "John" }, + ]); +}); + +test("Execute SQL Query with ORDER BY and WHERE", async () => { + const query = "SELECT name FROM student WHERE age > 24 ORDER BY name DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([{ name: "John" }, { name: "Jane" }]); +}); +test("Execute SQL Query with ORDER BY and GROUP BY", async () => { + const query = + "SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { age: "30", "COUNT(id) as count": 1 }, + { age: "25", "COUNT(id) as count": 1 }, + { age: "24", "COUNT(id) as count": 1 }, + { age: "22", "COUNT(id) as count": 1 }, + ]); +}); + +test("Execute SQL Query with standard LIMIT clause", async () => { + const query = "SELECT id, name FROM student LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with LIMIT clause equal to total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 4"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LIMIT clause exceeding total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 10"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); // Total rows in student.csv +}); + +test("Execute SQL Query with LIMIT 0", async () => { + const query = "SELECT id, name FROM student LIMIT 0"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(0); +}); + +test("Execute SQL Query with LIMIT and ORDER BY clause", async () => { + const query = "SELECT id, name FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); + expect(result[0].name).toEqual("John"); + expect(result[1].name).toEqual("Jane"); +}); + +test("Error Handling with Malformed Query", async () => { + const query = "SELECT FROM table"; // intentionally malformed + await expect(executeSELECTQuery(query)).rejects.toThrow( + "Error executing query: Query parsing error: Invalid SELECT format" + ); +}); + +test("Basic DISTINCT Usage", async () => { + const query = "SELECT DISTINCT age FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "30" }, + { age: "25" }, + { age: "22" }, + { age: "24" }, + ]); +}); + +test("DISTINCT with Multiple Columns", async () => { + const query = "SELECT DISTINCT student_id, course FROM enrollment"; + const result = await executeSELECTQuery(query); + // Expecting unique combinations of student_id and course + expect(result).toEqual([ + { student_id: "1", course: "Mathematics" }, + { student_id: "1", course: "Physics" }, + { student_id: "2", course: "Chemistry" }, + { student_id: "3", course: "Mathematics" }, + { student_id: "5", course: "Biology" }, + ]); }); // Not a good test right now -test('DISTINCT with WHERE Clause', async () => { - const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; - const result = await executeSELECTQuery(query); - // Expecting courses taken by student with ID 1 - expect(result).toEqual([{ course: 'Mathematics' }, { course: 'Physics' }]); +test("DISTINCT with WHERE Clause", async () => { + const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; + const result = await executeSELECTQuery(query); + // Expecting courses taken by student with ID 1 + expect(result).toEqual([{ course: "Mathematics" }, { course: "Physics" }]); }); -test('DISTINCT with JOIN Operations', async () => { - const query = 'SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id'; - const result = await executeSELECTQuery(query); - // Expecting names of students who are enrolled in any course - expect(result).toEqual([{ "student.name": 'John' }, { "student.name": 'Jane' }, { "student.name": 'Bob' }]); +test("DISTINCT with JOIN Operations", async () => { + const query = + "SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id"; + const result = await executeSELECTQuery(query); + // Expecting names of students who are enrolled in any course + expect(result).toEqual([ + { "student.name": "John" }, + { "student.name": "Jane" }, + { "student.name": "Bob" }, + ]); }); -test('DISTINCT with ORDER BY and LIMIT', async () => { - const query = 'SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - // Expecting the two highest unique ages - expect(result).toEqual([{ age: '30' }, { age: '25' }]); +test("DISTINCT with ORDER BY and LIMIT", async () => { + const query = "SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the two highest unique ages + expect(result).toEqual([{ age: "30" }, { age: "25" }]); }); -test('Execute SQL Query with LIKE Operator for Name', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; - const result = await executeSELECTQuery(query); - // Expecting names containing 'Jane' - expect(result).toEqual([{ name: 'Jane' }]); +test("Execute SQL Query with LIKE Operator for Name", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; + const result = await executeSELECTQuery(query); + // Expecting names containing 'Jane' + expect(result).toEqual([{ name: "Jane" }]); }); -test('Execute SQL Query with LIKE Operator and Wildcards', async () => { - const query = "SELECT name FROM student WHERE name LIKE 'J%'"; - const result = await executeSELECTQuery(query); - // Expecting names starting with 'J' - expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +test("Execute SQL Query with LIKE Operator and Wildcards", async () => { + const query = "SELECT name FROM student WHERE name LIKE 'J%'"; + const result = await executeSELECTQuery(query); + // Expecting names starting with 'J' + expect(result).toEqual([{ name: "John" }, { name: "Jane" }]); }); -test('Execute SQL Query with LIKE Operator Case Insensitive', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%bob%'"; - const result = await executeSELECTQuery(query); - // Expecting names 'Bob' (case insensitive) - expect(result).toEqual([{ name: 'Bob' }]); +test("Execute SQL Query with LIKE Operator Case Insensitive", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%bob%'"; + const result = await executeSELECTQuery(query); + // Expecting names 'Bob' (case insensitive) + expect(result).toEqual([{ name: "Bob" }]); }); -test('Execute SQL Query with LIKE Operator and DISTINCT', async () => { - const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%'"; - const result = await executeSELECTQuery(query); - // Expecting unique names containing 'e' - expect(result).toEqual([{ name: 'Jane' }, { name: 'Alice' }]); +test("Execute SQL Query with LIKE Operator and DISTINCT", async () => { + const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%'"; + const result = await executeSELECTQuery(query); + // Expecting unique names containing 'e' + expect(result).toEqual([{ name: "Jane" }, { name: "Alice" }]); }); -test('LIKE with ORDER BY and LIMIT', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%a%' ORDER BY name ASC LIMIT 2"; - const result = await executeSELECTQuery(query); - // Expecting the first two names alphabetically that contain 'a' - expect(result).toEqual([{ name: 'Alice' }, { name: 'Jane' }]); -}); \ No newline at end of file +test("LIKE with ORDER BY and LIMIT", async () => { + const query = + "SELECT name FROM student WHERE name LIKE '%a%' ORDER BY name ASC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the first two names alphabetically that contain 'a' + expect(result).toEqual([{ name: "Alice" }, { name: "Jane" }]); +}); diff --git a/tests/step-17/index.test.js b/tests/step-17/index.test.js index c99d01fbb..677604fb2 100644 --- a/tests/step-17/index.test.js +++ b/tests/step-17/index.test.js @@ -1,59 +1,60 @@ -const {readCSV} = require('../../src/csvReader'); -const {executeSELECTQuery } = require('../../src/index'); -const { parseJoinClause, parseSelectQuery } = require('../../src/queryParser'); - -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(4); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); - -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); - -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('id'); -}); - -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('name'); -}); - -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +const { readCSV } = require("../../src/csvReader"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); +const { parseJoinClause, parseSelectQuery } = require("../../src/queryParser"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -61,18 +62,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -86,737 +90,812 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); - -test('Execute SQL Query with RIGHT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": null, "enrollment.course": "Biology" }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "John" }), - expect.objectContaining({ "enrollment.course": "Physics", "student.name": "John" }) - ])); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "John", "enrollment.course": "Physics" }) - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "Bob" }), - expect.objectContaining({ "enrollment.course": "Biology", "student.name": null }) - ])); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Chemistry", "student.name": "Jane" }), - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; - const result = await executeSELECTQuery(query); - expect(result).toEqual([]); -}); - -test('Execute COUNT Aggregate Query', async () => { - const query = 'SELECT COUNT(*) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'COUNT(*)': 4 }]); -}); - -test('Execute SUM Aggregate Query', async () => { - const query = 'SELECT SUM(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'SUM(age)': 101 }]); -}); - -test('Execute AVG Aggregate Query', async () => { - const query = 'SELECT AVG(age) FROM student'; - const result = await executeSELECTQuery(query); - // Assuming AVG returns a single decimal point value - expect(result).toEqual([{ 'AVG(age)': 25.25 }]); -}); - -test('Execute MIN Aggregate Query', async () => { - const query = 'SELECT MIN(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MIN(age)': 22 }]); -}); - -test('Execute MAX Aggregate Query', async () => { - const query = 'SELECT MAX(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MAX(age)': 30 }]); -}); - -test('Count students per age', async () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '22', 'COUNT(*)': 1 }, - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments per course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 }, - { course: 'Physics', 'COUNT(*)': 1 }, - { course: 'Chemistry', 'COUNT(*)': 1 }, - { course: 'Biology', 'COUNT(*)': 1 } - ]); -}); - - -test('Count courses per student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 }, - { student_id: '2', 'COUNT(*)': 1 }, - { student_id: '3', 'COUNT(*)': 1 }, - { student_id: '5', 'COUNT(*)': 1 } - ]); -}); - -test('Count students within a specific age range', async () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments for a specific course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 } - ]); -}); - -test('Count courses for a specific student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 } - ]); -}); - -test('Average age of students above a certain age', async () => { - const query = 'SELECT AVG(age) FROM student WHERE age > 22'; - const result = await executeSELECTQuery(query); - const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 - expect(result).toEqual([{ 'AVG(age)': expectedAverage }]); -}); - -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", }) -}); - -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}); - -test('Parse INNER JOIN clause', () => { - const query = 'SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'INNER', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' }, - }); -}); - -test('Parse LEFT JOIN clause', () => { - const query = 'SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'LEFT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Parse RIGHT JOIN clause', () => { - const query = 'SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'RIGHT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Returns null for queries without JOIN', () => { - const query = 'SELECT * FROM table1'; - const result = parseJoinClause(query); - expect(result).toEqual( - { - joinType: null, - joinTable: null, - joinCondition: null - } - ); -}); - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'LEFT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'RIGHT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse COUNT Aggregate Query', () => { - const query = 'SELECT COUNT(*) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse SUM Aggregate Query', () => { - const query = 'SELECT SUM(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['SUM(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse AVG Aggregate Query', () => { - const query = 'SELECT AVG(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['AVG(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MIN Aggregate Query', () => { - const query = 'SELECT MIN(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['MIN(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MAX Aggregate Query', () => { - const query = 'SELECT MAX(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['MAX(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse basic GROUP BY query', () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with WHERE clause', () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'age', operator: '>', value: '22' }], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with multiple fields', () => { - const query = 'SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['student_id', 'course', 'COUNT(*)'], - table: 'enrollment', - whereClauses: [], - groupByFields: ['student_id', 'course'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with JOIN and WHERE clauses', () => { - const query = 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['student.name', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'enrollment.course', operator: '=', value: '"Mathematics"' }], - groupByFields: ['student.name'], - joinType: 'INNER', - joinTable: 'enrollment', - joinCondition: { - left: 'student.id', - right: 'enrollment.student_id' - }, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false, - }); -}); - -test('Execute SQL Query with ORDER BY', async () => { - const query = 'SELECT name FROM student ORDER BY name ASC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Jane' }, - { name: 'John' } - ]); -}); - -test('Execute SQL Query with ORDER BY and WHERE', async () => { - const query = 'SELECT name FROM student WHERE age > 24 ORDER BY name DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'John' }, - { name: 'Jane' }, - ]); -}); -test('Execute SQL Query with ORDER BY and GROUP BY', async () => { - const query = 'SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { age: '30', 'COUNT(id) as count': 1 }, - { age: '25', 'COUNT(id) as count': 1 }, - { age: '24', 'COUNT(id) as count': 1 }, - { age: '22', 'COUNT(id) as count': 1 } - ]); -}); - -test('Execute SQL Query with standard LIMIT clause', async () => { - const query = 'SELECT id, name FROM student LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with LIMIT clause equal to total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 4'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LIMIT clause exceeding total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 10'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); // Total rows in student.csv -}); - -test('Execute SQL Query with LIMIT 0', async () => { - const query = 'SELECT id, name FROM student LIMIT 0'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(0); -}); - -test('Execute SQL Query with LIMIT and ORDER BY clause', async () => { - const query = 'SELECT id, name FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); - expect(result[0].name).toEqual('John'); - expect(result[1].name).toEqual('Jane'); -}); - -test('Error Handling with Malformed Query', async () => { - const query = 'SELECT FROM table'; // intentionally malformed - await expect(executeSELECTQuery(query)).rejects.toThrow("Error executing query: Query parsing error: Invalid SELECT format"); -}); - -test('Basic DISTINCT Usage', async () => { - const query = 'SELECT DISTINCT age FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ age: '30' }, { age: '25' }, { age: '22' }, { age: '24' }]); -}); - -test('DISTINCT with Multiple Columns', async () => { - const query = 'SELECT DISTINCT student_id, course FROM enrollment'; - const result = await executeSELECTQuery(query); - // Expecting unique combinations of student_id and course - expect(result).toEqual([ - { student_id: '1', course: 'Mathematics' }, - { student_id: '1', course: 'Physics' }, - { student_id: '2', course: 'Chemistry' }, - { student_id: '3', course: 'Mathematics' }, - { student_id: '5', course: 'Biology' }, - ]); + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": null, + "enrollment.course": "Biology", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "enrollment.course": "Physics", + "student.name": "John", + }), + ]) + ); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Physics", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); + +test("Execute COUNT Aggregate Query", async () => { + const query = "SELECT COUNT(*) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "COUNT(*)": 4 }]); +}); + +test("Execute SUM Aggregate Query", async () => { + const query = "SELECT SUM(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "SUM(age)": 101 }]); +}); + +test("Execute AVG Aggregate Query", async () => { + const query = "SELECT AVG(age) FROM student"; + const result = await executeSELECTQuery(query); + // Assuming AVG returns a single decimal point value + expect(result).toEqual([{ "AVG(age)": 25.25 }]); +}); + +test("Execute MIN Aggregate Query", async () => { + const query = "SELECT MIN(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MIN(age)": 22 }]); +}); + +test("Execute MAX Aggregate Query", async () => { + const query = "SELECT MAX(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MAX(age)": 30 }]); +}); + +test("Count students per age", async () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "22", "COUNT(*)": 1 }, + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments per course", async () => { + const query = "SELECT course, COUNT(*) FROM enrollment GROUP BY course"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { course: "Mathematics", "COUNT(*)": 2 }, + { course: "Physics", "COUNT(*)": 1 }, + { course: "Chemistry", "COUNT(*)": 1 }, + { course: "Biology", "COUNT(*)": 1 }, + ]); +}); + +test("Count courses per student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { student_id: "1", "COUNT(*)": 2 }, + { student_id: "2", "COUNT(*)": 1 }, + { student_id: "3", "COUNT(*)": 1 }, + { student_id: "5", "COUNT(*)": 1 }, + ]); +}); + +test("Count students within a specific age range", async () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments for a specific course", async () => { + const query = + 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ course: "Mathematics", "COUNT(*)": 2 }]); +}); + +test("Count courses for a specific student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ student_id: "1", "COUNT(*)": 2 }]); +}); + +test("Average age of students above a certain age", async () => { + const query = "SELECT AVG(age) FROM student WHERE age > 22"; + const result = await executeSELECTQuery(query); + const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 + expect(result).toEqual([{ "AVG(age)": expectedAverage }]); +}); + +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse INNER JOIN clause", () => { + const query = + "SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "INNER", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse LEFT JOIN clause", () => { + const query = + "SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "LEFT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse RIGHT JOIN clause", () => { + const query = + "SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "RIGHT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Returns null for queries without JOIN", () => { + const query = "SELECT * FROM table1"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: null, + joinTable: null, + joinCondition: null, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "LEFT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "RIGHT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "22" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Physics'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [{ field: "student.age", operator: "<", value: "25" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Chemistry'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse COUNT Aggregate Query", () => { + const query = "SELECT COUNT(*) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SUM Aggregate Query", () => { + const query = "SELECT SUM(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["SUM(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse AVG Aggregate Query", () => { + const query = "SELECT AVG(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["AVG(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MIN Aggregate Query", () => { + const query = "SELECT MIN(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MIN(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MAX Aggregate Query", () => { + const query = "SELECT MAX(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MAX(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse basic GROUP BY query", () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with WHERE clause", () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [{ field: "age", operator: ">", value: "22" }], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with multiple fields", () => { + const query = + "SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course", "COUNT(*)"], + table: "enrollment", + whereClauses: [], + groupByFields: ["student_id", "course"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with JOIN and WHERE clauses", () => { + const query = + 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name", "COUNT(*)"], + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: '"Mathematics"' }, + ], + groupByFields: ["student.name"], + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query with ORDER BY", async () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { name: "Alice" }, + { name: "Bob" }, + { name: "Jane" }, + { name: "John" }, + ]); +}); + +test("Execute SQL Query with ORDER BY and WHERE", async () => { + const query = "SELECT name FROM student WHERE age > 24 ORDER BY name DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([{ name: "John" }, { name: "Jane" }]); +}); +test("Execute SQL Query with ORDER BY and GROUP BY", async () => { + const query = + "SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { age: "30", "COUNT(id) as count": 1 }, + { age: "25", "COUNT(id) as count": 1 }, + { age: "24", "COUNT(id) as count": 1 }, + { age: "22", "COUNT(id) as count": 1 }, + ]); +}); + +test("Execute SQL Query with standard LIMIT clause", async () => { + const query = "SELECT id, name FROM student LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with LIMIT clause equal to total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 4"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LIMIT clause exceeding total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 10"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); // Total rows in student.csv +}); + +test("Execute SQL Query with LIMIT 0", async () => { + const query = "SELECT id, name FROM student LIMIT 0"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(0); +}); + +test("Execute SQL Query with LIMIT and ORDER BY clause", async () => { + const query = "SELECT id, name FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); + expect(result[0].name).toEqual("John"); + expect(result[1].name).toEqual("Jane"); +}); + +test("Error Handling with Malformed Query", async () => { + const query = "SELECT FROM table"; // intentionally malformed + await expect(executeSELECTQuery(query)).rejects.toThrow( + "Error executing query: Query parsing error: Invalid SELECT format" + ); +}); + +test("Basic DISTINCT Usage", async () => { + const query = "SELECT DISTINCT age FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "30" }, + { age: "25" }, + { age: "22" }, + { age: "24" }, + ]); +}); + +test("DISTINCT with Multiple Columns", async () => { + const query = "SELECT DISTINCT student_id, course FROM enrollment"; + const result = await executeSELECTQuery(query); + // Expecting unique combinations of student_id and course + expect(result).toEqual([ + { student_id: "1", course: "Mathematics" }, + { student_id: "1", course: "Physics" }, + { student_id: "2", course: "Chemistry" }, + { student_id: "3", course: "Mathematics" }, + { student_id: "5", course: "Biology" }, + ]); }); // Not a good test right now -test('DISTINCT with WHERE Clause', async () => { - const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; - const result = await executeSELECTQuery(query); - // Expecting courses taken by student with ID 1 - expect(result).toEqual([{ course: 'Mathematics' }, { course: 'Physics' }]); +test("DISTINCT with WHERE Clause", async () => { + const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; + const result = await executeSELECTQuery(query); + // Expecting courses taken by student with ID 1 + expect(result).toEqual([{ course: "Mathematics" }, { course: "Physics" }]); }); -test('DISTINCT with JOIN Operations', async () => { - const query = 'SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id'; - const result = await executeSELECTQuery(query); - // Expecting names of students who are enrolled in any course - expect(result).toEqual([{ "student.name": 'John' }, { "student.name": 'Jane' }, { "student.name": 'Bob' }]); +test("DISTINCT with JOIN Operations", async () => { + const query = + "SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id"; + const result = await executeSELECTQuery(query); + // Expecting names of students who are enrolled in any course + expect(result).toEqual([ + { "student.name": "John" }, + { "student.name": "Jane" }, + { "student.name": "Bob" }, + ]); }); -test('DISTINCT with ORDER BY and LIMIT', async () => { - const query = 'SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - // Expecting the two highest unique ages - expect(result).toEqual([{ age: '30' }, { age: '25' }]); +test("DISTINCT with ORDER BY and LIMIT", async () => { + const query = "SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the two highest unique ages + expect(result).toEqual([{ age: "30" }, { age: "25" }]); }); -test('Execute SQL Query with LIKE Operator for Name', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; - const result = await executeSELECTQuery(query); - // Expecting names containing 'Jane' - expect(result).toEqual([{ name: 'Jane' }]); +test("Execute SQL Query with LIKE Operator for Name", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; + const result = await executeSELECTQuery(query); + // Expecting names containing 'Jane' + expect(result).toEqual([{ name: "Jane" }]); }); -test('Execute SQL Query with LIKE Operator and Wildcards', async () => { - const query = "SELECT name FROM student WHERE name LIKE 'J%'"; - const result = await executeSELECTQuery(query); - // Expecting names starting with 'J' - expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +test("Execute SQL Query with LIKE Operator and Wildcards", async () => { + const query = "SELECT name FROM student WHERE name LIKE 'J%'"; + const result = await executeSELECTQuery(query); + // Expecting names starting with 'J' + expect(result).toEqual([{ name: "John" }, { name: "Jane" }]); }); -test('Execute SQL Query with LIKE Operator Case Insensitive', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%bob%'"; - const result = await executeSELECTQuery(query); - // Expecting names 'Bob' (case insensitive) - expect(result).toEqual([{ name: 'Bob' }]); +test("Execute SQL Query with LIKE Operator Case Insensitive", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%bob%'"; + const result = await executeSELECTQuery(query); + // Expecting names 'Bob' (case insensitive) + expect(result).toEqual([{ name: "Bob" }]); }); -test('Execute SQL Query with LIKE Operator and DISTINCT', async () => { - const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%'"; - const result = await executeSELECTQuery(query); - // Expecting unique names containing 'e' - expect(result).toEqual([{ name: 'Jane' }, { name: 'Alice' }]); +test("Execute SQL Query with LIKE Operator and DISTINCT", async () => { + const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%'"; + const result = await executeSELECTQuery(query); + // Expecting unique names containing 'e' + expect(result).toEqual([{ name: "Jane" }, { name: "Alice" }]); }); -test('LIKE with ORDER BY and LIMIT', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%a%' ORDER BY name ASC LIMIT 2"; - const result = await executeSELECTQuery(query); - // Expecting the first two names alphabetically that contain 'a' - expect(result).toEqual([{ name: 'Alice' }, { name: 'Jane' }]); -}); \ No newline at end of file +test("LIKE with ORDER BY and LIMIT", async () => { + const query = + "SELECT name FROM student WHERE name LIKE '%a%' ORDER BY name ASC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the first two names alphabetically that contain 'a' + expect(result).toEqual([{ name: "Alice" }, { name: "Jane" }]); +}); diff --git a/tests/step-17/insertExecuter.test.js b/tests/step-17/insertExecuter.test.js index 8c405f727..473314045 100644 --- a/tests/step-17/insertExecuter.test.js +++ b/tests/step-17/insertExecuter.test.js @@ -1,33 +1,36 @@ -const { executeINSERTQuery } = require('../../src/index'); -const { readCSV, writeCSV } = require('../../src/csvReader'); -const fs = require('fs'); +const { executeINSERTQuery } = require("../../src/queryExecutor"); +const { readCSV, writeCSV } = require("../../src/csvReader"); +const fs = require("fs"); // Helper function to create grades.csv with initial data async function createGradesCSV() { - const initialData = [ - { student_id: '1', course: 'Mathematics', grade: 'A' }, - { student_id: '2', course: 'Chemistry', grade: 'B' }, - { student_id: '3', course: 'Mathematics', grade: 'C' } - ]; - await writeCSV('grades.csv', initialData); + const initialData = [ + { student_id: "1", course: "Mathematics", grade: "A" }, + { student_id: "2", course: "Chemistry", grade: "B" }, + { student_id: "3", course: "Mathematics", grade: "C" }, + ]; + await writeCSV("grades.csv", initialData); } // Test to INSERT a new grade and verify -test('Execute INSERT INTO Query for grades.csv', async () => { - // Create grades.csv with initial data - await createGradesCSV(); +test("Execute INSERT INTO Query for grades.csv", async () => { + // Create grades.csv with initial data + await createGradesCSV(); - // Execute INSERT statement - const insertQuery = "INSERT INTO grades (student_id, course, grade) VALUES ('4', 'Physics', 'A')"; - await executeINSERTQuery(insertQuery); + // Execute INSERT statement + const insertQuery = + "INSERT INTO grades (student_id, course, grade) VALUES ('4', 'Physics', 'A')"; + await executeINSERTQuery(insertQuery); - // Verify the new entry - const updatedData = await readCSV('grades.csv'); - const newEntry = updatedData.find(row => row.student_id === '4' && row.course === 'Physics'); - console.log(updatedData) - expect(newEntry).toBeDefined(); - expect(newEntry.grade).toEqual('A'); + // Verify the new entry + const updatedData = await readCSV("grades.csv"); + const newEntry = updatedData.find( + (row) => row.student_id === "4" && row.course === "Physics" + ); - // Cleanup: Delete grades.csv - fs.unlinkSync('grades.csv'); -}); \ No newline at end of file + expect(newEntry).toBeDefined(); + expect(newEntry.grade).toEqual("A"); + + // Cleanup: Delete grades.csv + fs.unlinkSync("grades.csv"); +}); diff --git a/tests/step-18/deleteExecutor.test.js b/tests/step-18/deleteExecutor.test.js index 11ae617b7..0e53a921e 100644 --- a/tests/step-18/deleteExecutor.test.js +++ b/tests/step-18/deleteExecutor.test.js @@ -1,31 +1,31 @@ -const { executeDELETEQuery } = require('../../src/index'); -const { readCSV, writeCSV } = require('../../src/csvReader'); -const fs = require('fs'); +const { executeDELETEQuery } = require("../../src/queryExecutor"); +const { readCSV, writeCSV } = require("../../src/csvReader"); +const fs = require("fs"); // Helper function to create courses.csv with initial data async function createCoursesCSV() { - const initialData = [ - { course_id: '1', course_name: 'Mathematics', instructor: 'Dr. Smith' }, - { course_id: '2', course_name: 'Chemistry', instructor: 'Dr. Jones' }, - { course_id: '3', course_name: 'Physics', instructor: 'Dr. Taylor' } - ]; - await writeCSV('courses.csv', initialData); + const initialData = [ + { course_id: "1", course_name: "Mathematics", instructor: "Dr. Smith" }, + { course_id: "2", course_name: "Chemistry", instructor: "Dr. Jones" }, + { course_id: "3", course_name: "Physics", instructor: "Dr. Taylor" }, + ]; + await writeCSV("courses.csv", initialData); } // Test to DELETE a course and verify -test('Execute DELETE FROM Query for courses.csv', async () => { - // Create courses.csv with initial data - await createCoursesCSV(); +test("Execute DELETE FROM Query for courses.csv", async () => { + // Create courses.csv with initial data + await createCoursesCSV(); - // Execute DELETE statement - const deleteQuery = "DELETE FROM courses WHERE course_id = '2'"; - await executeDELETEQuery(deleteQuery); + // Execute DELETE statement + const deleteQuery = "DELETE FROM courses WHERE course_id = '2'"; + await executeDELETEQuery(deleteQuery); - // Verify the course was removed - const updatedData = await readCSV('courses.csv'); - const deletedCourse = updatedData.find(course => course.course_id === '2'); - expect(deletedCourse).toBeUndefined(); + // Verify the course was removed + const updatedData = await readCSV("courses.csv"); + const deletedCourse = updatedData.find((course) => course.course_id === "2"); + expect(deletedCourse).toBeUndefined(); - // Cleanup: Delete courses.csv - fs.unlinkSync('courses.csv'); -}); \ No newline at end of file + // Cleanup: Delete courses.csv + fs.unlinkSync("courses.csv"); +}); diff --git a/tests/step-18/index.test.js b/tests/step-18/index.test.js index c99d01fbb..677604fb2 100644 --- a/tests/step-18/index.test.js +++ b/tests/step-18/index.test.js @@ -1,59 +1,60 @@ -const {readCSV} = require('../../src/csvReader'); -const {executeSELECTQuery } = require('../../src/index'); -const { parseJoinClause, parseSelectQuery } = require('../../src/queryParser'); - -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(4); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); - -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); - -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('id'); -}); - -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('name'); -}); - -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +const { readCSV } = require("../../src/csvReader"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); +const { parseJoinClause, parseSelectQuery } = require("../../src/queryParser"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -61,18 +62,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -86,737 +90,812 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); - -test('Execute SQL Query with RIGHT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": null, "enrollment.course": "Biology" }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "John" }), - expect.objectContaining({ "enrollment.course": "Physics", "student.name": "John" }) - ])); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "John", "enrollment.course": "Physics" }) - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "Bob" }), - expect.objectContaining({ "enrollment.course": "Biology", "student.name": null }) - ])); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Chemistry", "student.name": "Jane" }), - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; - const result = await executeSELECTQuery(query); - expect(result).toEqual([]); -}); - -test('Execute COUNT Aggregate Query', async () => { - const query = 'SELECT COUNT(*) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'COUNT(*)': 4 }]); -}); - -test('Execute SUM Aggregate Query', async () => { - const query = 'SELECT SUM(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'SUM(age)': 101 }]); -}); - -test('Execute AVG Aggregate Query', async () => { - const query = 'SELECT AVG(age) FROM student'; - const result = await executeSELECTQuery(query); - // Assuming AVG returns a single decimal point value - expect(result).toEqual([{ 'AVG(age)': 25.25 }]); -}); - -test('Execute MIN Aggregate Query', async () => { - const query = 'SELECT MIN(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MIN(age)': 22 }]); -}); - -test('Execute MAX Aggregate Query', async () => { - const query = 'SELECT MAX(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MAX(age)': 30 }]); -}); - -test('Count students per age', async () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '22', 'COUNT(*)': 1 }, - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments per course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 }, - { course: 'Physics', 'COUNT(*)': 1 }, - { course: 'Chemistry', 'COUNT(*)': 1 }, - { course: 'Biology', 'COUNT(*)': 1 } - ]); -}); - - -test('Count courses per student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 }, - { student_id: '2', 'COUNT(*)': 1 }, - { student_id: '3', 'COUNT(*)': 1 }, - { student_id: '5', 'COUNT(*)': 1 } - ]); -}); - -test('Count students within a specific age range', async () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments for a specific course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 } - ]); -}); - -test('Count courses for a specific student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 } - ]); -}); - -test('Average age of students above a certain age', async () => { - const query = 'SELECT AVG(age) FROM student WHERE age > 22'; - const result = await executeSELECTQuery(query); - const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 - expect(result).toEqual([{ 'AVG(age)': expectedAverage }]); -}); - -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", }) -}); - -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}); - -test('Parse INNER JOIN clause', () => { - const query = 'SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'INNER', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' }, - }); -}); - -test('Parse LEFT JOIN clause', () => { - const query = 'SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'LEFT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Parse RIGHT JOIN clause', () => { - const query = 'SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'RIGHT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Returns null for queries without JOIN', () => { - const query = 'SELECT * FROM table1'; - const result = parseJoinClause(query); - expect(result).toEqual( - { - joinType: null, - joinTable: null, - joinCondition: null - } - ); -}); - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'LEFT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'RIGHT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse COUNT Aggregate Query', () => { - const query = 'SELECT COUNT(*) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse SUM Aggregate Query', () => { - const query = 'SELECT SUM(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['SUM(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse AVG Aggregate Query', () => { - const query = 'SELECT AVG(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['AVG(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MIN Aggregate Query', () => { - const query = 'SELECT MIN(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['MIN(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MAX Aggregate Query', () => { - const query = 'SELECT MAX(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['MAX(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse basic GROUP BY query', () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with WHERE clause', () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'age', operator: '>', value: '22' }], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with multiple fields', () => { - const query = 'SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['student_id', 'course', 'COUNT(*)'], - table: 'enrollment', - whereClauses: [], - groupByFields: ['student_id', 'course'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with JOIN and WHERE clauses', () => { - const query = 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['student.name', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'enrollment.course', operator: '=', value: '"Mathematics"' }], - groupByFields: ['student.name'], - joinType: 'INNER', - joinTable: 'enrollment', - joinCondition: { - left: 'student.id', - right: 'enrollment.student_id' - }, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false, - }); -}); - -test('Execute SQL Query with ORDER BY', async () => { - const query = 'SELECT name FROM student ORDER BY name ASC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Jane' }, - { name: 'John' } - ]); -}); - -test('Execute SQL Query with ORDER BY and WHERE', async () => { - const query = 'SELECT name FROM student WHERE age > 24 ORDER BY name DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'John' }, - { name: 'Jane' }, - ]); -}); -test('Execute SQL Query with ORDER BY and GROUP BY', async () => { - const query = 'SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { age: '30', 'COUNT(id) as count': 1 }, - { age: '25', 'COUNT(id) as count': 1 }, - { age: '24', 'COUNT(id) as count': 1 }, - { age: '22', 'COUNT(id) as count': 1 } - ]); -}); - -test('Execute SQL Query with standard LIMIT clause', async () => { - const query = 'SELECT id, name FROM student LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with LIMIT clause equal to total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 4'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LIMIT clause exceeding total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 10'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); // Total rows in student.csv -}); - -test('Execute SQL Query with LIMIT 0', async () => { - const query = 'SELECT id, name FROM student LIMIT 0'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(0); -}); - -test('Execute SQL Query with LIMIT and ORDER BY clause', async () => { - const query = 'SELECT id, name FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); - expect(result[0].name).toEqual('John'); - expect(result[1].name).toEqual('Jane'); -}); - -test('Error Handling with Malformed Query', async () => { - const query = 'SELECT FROM table'; // intentionally malformed - await expect(executeSELECTQuery(query)).rejects.toThrow("Error executing query: Query parsing error: Invalid SELECT format"); -}); - -test('Basic DISTINCT Usage', async () => { - const query = 'SELECT DISTINCT age FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ age: '30' }, { age: '25' }, { age: '22' }, { age: '24' }]); -}); - -test('DISTINCT with Multiple Columns', async () => { - const query = 'SELECT DISTINCT student_id, course FROM enrollment'; - const result = await executeSELECTQuery(query); - // Expecting unique combinations of student_id and course - expect(result).toEqual([ - { student_id: '1', course: 'Mathematics' }, - { student_id: '1', course: 'Physics' }, - { student_id: '2', course: 'Chemistry' }, - { student_id: '3', course: 'Mathematics' }, - { student_id: '5', course: 'Biology' }, - ]); + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": null, + "enrollment.course": "Biology", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "enrollment.course": "Physics", + "student.name": "John", + }), + ]) + ); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Physics", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); + +test("Execute COUNT Aggregate Query", async () => { + const query = "SELECT COUNT(*) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "COUNT(*)": 4 }]); +}); + +test("Execute SUM Aggregate Query", async () => { + const query = "SELECT SUM(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "SUM(age)": 101 }]); +}); + +test("Execute AVG Aggregate Query", async () => { + const query = "SELECT AVG(age) FROM student"; + const result = await executeSELECTQuery(query); + // Assuming AVG returns a single decimal point value + expect(result).toEqual([{ "AVG(age)": 25.25 }]); +}); + +test("Execute MIN Aggregate Query", async () => { + const query = "SELECT MIN(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MIN(age)": 22 }]); +}); + +test("Execute MAX Aggregate Query", async () => { + const query = "SELECT MAX(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MAX(age)": 30 }]); +}); + +test("Count students per age", async () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "22", "COUNT(*)": 1 }, + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments per course", async () => { + const query = "SELECT course, COUNT(*) FROM enrollment GROUP BY course"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { course: "Mathematics", "COUNT(*)": 2 }, + { course: "Physics", "COUNT(*)": 1 }, + { course: "Chemistry", "COUNT(*)": 1 }, + { course: "Biology", "COUNT(*)": 1 }, + ]); +}); + +test("Count courses per student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { student_id: "1", "COUNT(*)": 2 }, + { student_id: "2", "COUNT(*)": 1 }, + { student_id: "3", "COUNT(*)": 1 }, + { student_id: "5", "COUNT(*)": 1 }, + ]); +}); + +test("Count students within a specific age range", async () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments for a specific course", async () => { + const query = + 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ course: "Mathematics", "COUNT(*)": 2 }]); +}); + +test("Count courses for a specific student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ student_id: "1", "COUNT(*)": 2 }]); +}); + +test("Average age of students above a certain age", async () => { + const query = "SELECT AVG(age) FROM student WHERE age > 22"; + const result = await executeSELECTQuery(query); + const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 + expect(result).toEqual([{ "AVG(age)": expectedAverage }]); +}); + +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse INNER JOIN clause", () => { + const query = + "SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "INNER", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse LEFT JOIN clause", () => { + const query = + "SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "LEFT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse RIGHT JOIN clause", () => { + const query = + "SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "RIGHT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Returns null for queries without JOIN", () => { + const query = "SELECT * FROM table1"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: null, + joinTable: null, + joinCondition: null, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "LEFT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "RIGHT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "22" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Physics'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [{ field: "student.age", operator: "<", value: "25" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Chemistry'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse COUNT Aggregate Query", () => { + const query = "SELECT COUNT(*) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SUM Aggregate Query", () => { + const query = "SELECT SUM(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["SUM(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse AVG Aggregate Query", () => { + const query = "SELECT AVG(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["AVG(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MIN Aggregate Query", () => { + const query = "SELECT MIN(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MIN(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MAX Aggregate Query", () => { + const query = "SELECT MAX(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MAX(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse basic GROUP BY query", () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with WHERE clause", () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [{ field: "age", operator: ">", value: "22" }], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with multiple fields", () => { + const query = + "SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course", "COUNT(*)"], + table: "enrollment", + whereClauses: [], + groupByFields: ["student_id", "course"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with JOIN and WHERE clauses", () => { + const query = + 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name", "COUNT(*)"], + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: '"Mathematics"' }, + ], + groupByFields: ["student.name"], + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query with ORDER BY", async () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { name: "Alice" }, + { name: "Bob" }, + { name: "Jane" }, + { name: "John" }, + ]); +}); + +test("Execute SQL Query with ORDER BY and WHERE", async () => { + const query = "SELECT name FROM student WHERE age > 24 ORDER BY name DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([{ name: "John" }, { name: "Jane" }]); +}); +test("Execute SQL Query with ORDER BY and GROUP BY", async () => { + const query = + "SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { age: "30", "COUNT(id) as count": 1 }, + { age: "25", "COUNT(id) as count": 1 }, + { age: "24", "COUNT(id) as count": 1 }, + { age: "22", "COUNT(id) as count": 1 }, + ]); +}); + +test("Execute SQL Query with standard LIMIT clause", async () => { + const query = "SELECT id, name FROM student LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with LIMIT clause equal to total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 4"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LIMIT clause exceeding total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 10"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); // Total rows in student.csv +}); + +test("Execute SQL Query with LIMIT 0", async () => { + const query = "SELECT id, name FROM student LIMIT 0"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(0); +}); + +test("Execute SQL Query with LIMIT and ORDER BY clause", async () => { + const query = "SELECT id, name FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); + expect(result[0].name).toEqual("John"); + expect(result[1].name).toEqual("Jane"); +}); + +test("Error Handling with Malformed Query", async () => { + const query = "SELECT FROM table"; // intentionally malformed + await expect(executeSELECTQuery(query)).rejects.toThrow( + "Error executing query: Query parsing error: Invalid SELECT format" + ); +}); + +test("Basic DISTINCT Usage", async () => { + const query = "SELECT DISTINCT age FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "30" }, + { age: "25" }, + { age: "22" }, + { age: "24" }, + ]); +}); + +test("DISTINCT with Multiple Columns", async () => { + const query = "SELECT DISTINCT student_id, course FROM enrollment"; + const result = await executeSELECTQuery(query); + // Expecting unique combinations of student_id and course + expect(result).toEqual([ + { student_id: "1", course: "Mathematics" }, + { student_id: "1", course: "Physics" }, + { student_id: "2", course: "Chemistry" }, + { student_id: "3", course: "Mathematics" }, + { student_id: "5", course: "Biology" }, + ]); }); // Not a good test right now -test('DISTINCT with WHERE Clause', async () => { - const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; - const result = await executeSELECTQuery(query); - // Expecting courses taken by student with ID 1 - expect(result).toEqual([{ course: 'Mathematics' }, { course: 'Physics' }]); +test("DISTINCT with WHERE Clause", async () => { + const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; + const result = await executeSELECTQuery(query); + // Expecting courses taken by student with ID 1 + expect(result).toEqual([{ course: "Mathematics" }, { course: "Physics" }]); }); -test('DISTINCT with JOIN Operations', async () => { - const query = 'SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id'; - const result = await executeSELECTQuery(query); - // Expecting names of students who are enrolled in any course - expect(result).toEqual([{ "student.name": 'John' }, { "student.name": 'Jane' }, { "student.name": 'Bob' }]); +test("DISTINCT with JOIN Operations", async () => { + const query = + "SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id"; + const result = await executeSELECTQuery(query); + // Expecting names of students who are enrolled in any course + expect(result).toEqual([ + { "student.name": "John" }, + { "student.name": "Jane" }, + { "student.name": "Bob" }, + ]); }); -test('DISTINCT with ORDER BY and LIMIT', async () => { - const query = 'SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - // Expecting the two highest unique ages - expect(result).toEqual([{ age: '30' }, { age: '25' }]); +test("DISTINCT with ORDER BY and LIMIT", async () => { + const query = "SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the two highest unique ages + expect(result).toEqual([{ age: "30" }, { age: "25" }]); }); -test('Execute SQL Query with LIKE Operator for Name', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; - const result = await executeSELECTQuery(query); - // Expecting names containing 'Jane' - expect(result).toEqual([{ name: 'Jane' }]); +test("Execute SQL Query with LIKE Operator for Name", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; + const result = await executeSELECTQuery(query); + // Expecting names containing 'Jane' + expect(result).toEqual([{ name: "Jane" }]); }); -test('Execute SQL Query with LIKE Operator and Wildcards', async () => { - const query = "SELECT name FROM student WHERE name LIKE 'J%'"; - const result = await executeSELECTQuery(query); - // Expecting names starting with 'J' - expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +test("Execute SQL Query with LIKE Operator and Wildcards", async () => { + const query = "SELECT name FROM student WHERE name LIKE 'J%'"; + const result = await executeSELECTQuery(query); + // Expecting names starting with 'J' + expect(result).toEqual([{ name: "John" }, { name: "Jane" }]); }); -test('Execute SQL Query with LIKE Operator Case Insensitive', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%bob%'"; - const result = await executeSELECTQuery(query); - // Expecting names 'Bob' (case insensitive) - expect(result).toEqual([{ name: 'Bob' }]); +test("Execute SQL Query with LIKE Operator Case Insensitive", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%bob%'"; + const result = await executeSELECTQuery(query); + // Expecting names 'Bob' (case insensitive) + expect(result).toEqual([{ name: "Bob" }]); }); -test('Execute SQL Query with LIKE Operator and DISTINCT', async () => { - const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%'"; - const result = await executeSELECTQuery(query); - // Expecting unique names containing 'e' - expect(result).toEqual([{ name: 'Jane' }, { name: 'Alice' }]); +test("Execute SQL Query with LIKE Operator and DISTINCT", async () => { + const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%'"; + const result = await executeSELECTQuery(query); + // Expecting unique names containing 'e' + expect(result).toEqual([{ name: "Jane" }, { name: "Alice" }]); }); -test('LIKE with ORDER BY and LIMIT', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%a%' ORDER BY name ASC LIMIT 2"; - const result = await executeSELECTQuery(query); - // Expecting the first two names alphabetically that contain 'a' - expect(result).toEqual([{ name: 'Alice' }, { name: 'Jane' }]); -}); \ No newline at end of file +test("LIKE with ORDER BY and LIMIT", async () => { + const query = + "SELECT name FROM student WHERE name LIKE '%a%' ORDER BY name ASC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the first two names alphabetically that contain 'a' + expect(result).toEqual([{ name: "Alice" }, { name: "Jane" }]); +}); diff --git a/tests/step-18/insertExecuter.test.js b/tests/step-18/insertExecuter.test.js index 8c405f727..473314045 100644 --- a/tests/step-18/insertExecuter.test.js +++ b/tests/step-18/insertExecuter.test.js @@ -1,33 +1,36 @@ -const { executeINSERTQuery } = require('../../src/index'); -const { readCSV, writeCSV } = require('../../src/csvReader'); -const fs = require('fs'); +const { executeINSERTQuery } = require("../../src/queryExecutor"); +const { readCSV, writeCSV } = require("../../src/csvReader"); +const fs = require("fs"); // Helper function to create grades.csv with initial data async function createGradesCSV() { - const initialData = [ - { student_id: '1', course: 'Mathematics', grade: 'A' }, - { student_id: '2', course: 'Chemistry', grade: 'B' }, - { student_id: '3', course: 'Mathematics', grade: 'C' } - ]; - await writeCSV('grades.csv', initialData); + const initialData = [ + { student_id: "1", course: "Mathematics", grade: "A" }, + { student_id: "2", course: "Chemistry", grade: "B" }, + { student_id: "3", course: "Mathematics", grade: "C" }, + ]; + await writeCSV("grades.csv", initialData); } // Test to INSERT a new grade and verify -test('Execute INSERT INTO Query for grades.csv', async () => { - // Create grades.csv with initial data - await createGradesCSV(); +test("Execute INSERT INTO Query for grades.csv", async () => { + // Create grades.csv with initial data + await createGradesCSV(); - // Execute INSERT statement - const insertQuery = "INSERT INTO grades (student_id, course, grade) VALUES ('4', 'Physics', 'A')"; - await executeINSERTQuery(insertQuery); + // Execute INSERT statement + const insertQuery = + "INSERT INTO grades (student_id, course, grade) VALUES ('4', 'Physics', 'A')"; + await executeINSERTQuery(insertQuery); - // Verify the new entry - const updatedData = await readCSV('grades.csv'); - const newEntry = updatedData.find(row => row.student_id === '4' && row.course === 'Physics'); - console.log(updatedData) - expect(newEntry).toBeDefined(); - expect(newEntry.grade).toEqual('A'); + // Verify the new entry + const updatedData = await readCSV("grades.csv"); + const newEntry = updatedData.find( + (row) => row.student_id === "4" && row.course === "Physics" + ); - // Cleanup: Delete grades.csv - fs.unlinkSync('grades.csv'); -}); \ No newline at end of file + expect(newEntry).toBeDefined(); + expect(newEntry.grade).toEqual("A"); + + // Cleanup: Delete grades.csv + fs.unlinkSync("grades.csv"); +}); diff --git a/tests/step-19/deleteExecutor.test.js b/tests/step-19/deleteExecutor.test.js index 11ae617b7..0e53a921e 100644 --- a/tests/step-19/deleteExecutor.test.js +++ b/tests/step-19/deleteExecutor.test.js @@ -1,31 +1,31 @@ -const { executeDELETEQuery } = require('../../src/index'); -const { readCSV, writeCSV } = require('../../src/csvReader'); -const fs = require('fs'); +const { executeDELETEQuery } = require("../../src/queryExecutor"); +const { readCSV, writeCSV } = require("../../src/csvReader"); +const fs = require("fs"); // Helper function to create courses.csv with initial data async function createCoursesCSV() { - const initialData = [ - { course_id: '1', course_name: 'Mathematics', instructor: 'Dr. Smith' }, - { course_id: '2', course_name: 'Chemistry', instructor: 'Dr. Jones' }, - { course_id: '3', course_name: 'Physics', instructor: 'Dr. Taylor' } - ]; - await writeCSV('courses.csv', initialData); + const initialData = [ + { course_id: "1", course_name: "Mathematics", instructor: "Dr. Smith" }, + { course_id: "2", course_name: "Chemistry", instructor: "Dr. Jones" }, + { course_id: "3", course_name: "Physics", instructor: "Dr. Taylor" }, + ]; + await writeCSV("courses.csv", initialData); } // Test to DELETE a course and verify -test('Execute DELETE FROM Query for courses.csv', async () => { - // Create courses.csv with initial data - await createCoursesCSV(); +test("Execute DELETE FROM Query for courses.csv", async () => { + // Create courses.csv with initial data + await createCoursesCSV(); - // Execute DELETE statement - const deleteQuery = "DELETE FROM courses WHERE course_id = '2'"; - await executeDELETEQuery(deleteQuery); + // Execute DELETE statement + const deleteQuery = "DELETE FROM courses WHERE course_id = '2'"; + await executeDELETEQuery(deleteQuery); - // Verify the course was removed - const updatedData = await readCSV('courses.csv'); - const deletedCourse = updatedData.find(course => course.course_id === '2'); - expect(deletedCourse).toBeUndefined(); + // Verify the course was removed + const updatedData = await readCSV("courses.csv"); + const deletedCourse = updatedData.find((course) => course.course_id === "2"); + expect(deletedCourse).toBeUndefined(); - // Cleanup: Delete courses.csv - fs.unlinkSync('courses.csv'); -}); \ No newline at end of file + // Cleanup: Delete courses.csv + fs.unlinkSync("courses.csv"); +}); diff --git a/tests/step-19/index.test.js b/tests/step-19/index.test.js index c99d01fbb..677604fb2 100644 --- a/tests/step-19/index.test.js +++ b/tests/step-19/index.test.js @@ -1,59 +1,60 @@ -const {readCSV} = require('../../src/csvReader'); -const {executeSELECTQuery } = require('../../src/index'); -const { parseJoinClause, parseSelectQuery } = require('../../src/queryParser'); - -test('Read CSV File', async () => { - const data = await readCSV('./student.csv'); - expect(data.length).toBeGreaterThan(0); - expect(data.length).toBe(4); - expect(data[0].name).toBe('John'); - expect(data[0].age).toBe('30'); //ignore the string type here, we will fix this later -}); - -test('Execute SQL Query', async () => { - const query = 'SELECT id, name FROM student'; - const result = await executeSELECTQuery(query); - expect(result.length).toBeGreaterThan(0); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0]).not.toHaveProperty('age'); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toHaveProperty('id'); - expect(result[0]).toHaveProperty('name'); - expect(result[0].id).toBe('2'); -}); - -test('Execute SQL Query with Complex WHERE Clause', async () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const result = await executeSELECTQuery(query); - expect(result.length).toBe(1); - expect(result[0]).toEqual({ id: '1', name: 'John' }); -}); - -test('Execute SQL Query with Greater Than', async () => { - const queryWithGT = 'SELECT id FROM student WHERE age > 22'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('id'); -}); - -test('Execute SQL Query with Not Equal to', async () => { - const queryWithGT = 'SELECT name FROM student WHERE age != 25'; - const result = await executeSELECTQuery(queryWithGT); - expect(result.length).toEqual(3); - expect(result[0]).toHaveProperty('name'); -}); - -test('Execute SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - /* +const { readCSV } = require("../../src/csvReader"); +const { executeSELECTQuery } = require("../../src/queryExecutor"); +const { parseJoinClause, parseSelectQuery } = require("../../src/queryParser"); + +test("Read CSV File", async () => { + const data = await readCSV("./student.csv"); + expect(data.length).toBeGreaterThan(0); + expect(data.length).toBe(4); + expect(data[0].name).toBe("John"); + expect(data[0].age).toBe("30"); //ignore the string type here, we will fix this later +}); + +test("Execute SQL Query", async () => { + const query = "SELECT id, name FROM student"; + const result = await executeSELECTQuery(query); + expect(result.length).toBeGreaterThan(0); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0]).not.toHaveProperty("age"); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toHaveProperty("id"); + expect(result[0]).toHaveProperty("name"); + expect(result[0].id).toBe("2"); +}); + +test("Execute SQL Query with Complex WHERE Clause", async () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const result = await executeSELECTQuery(query); + expect(result.length).toBe(1); + expect(result[0]).toEqual({ id: "1", name: "John" }); +}); + +test("Execute SQL Query with Greater Than", async () => { + const queryWithGT = "SELECT id FROM student WHERE age > 22"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("id"); +}); + +test("Execute SQL Query with Not Equal to", async () => { + const queryWithGT = "SELECT name FROM student WHERE age != 25"; + const result = await executeSELECTQuery(queryWithGT); + expect(result.length).toEqual(3); + expect(result[0]).toHaveProperty("name"); +}); + +test("Execute SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', 'enrollment.course': 'Mathematics' }, { 'student.name': 'John', 'enrollment.course': 'Physics' }, @@ -61,18 +62,21 @@ test('Execute SQL Query with INNER JOIN', async () => { { 'student.name': 'Bob', 'enrollment.course': 'Mathematics' } ] */ - expect(result.length).toEqual(4); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); + expect(result.length).toEqual(4); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }) + ); }); -test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25'; - const result = await executeSELECTQuery(query); - /* +test("Execute SQL Query with INNER JOIN and a WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course, student.age FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 25"; + const result = await executeSELECTQuery(query); + /* result = [ { 'student.name': 'John', @@ -86,737 +90,812 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => { } ] */ - expect(result.length).toEqual(2); - // toHaveProperty is not working here due to dot in the property name - expect(result[0]).toEqual(expect.objectContaining({ - "enrollment.course": "Mathematics", - "student.name": "John" - })); -}); - -test('Execute SQL Query with LEFT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "Alice", "enrollment.course": null }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 students, but John appears twice -}); - -test('Execute SQL Query with RIGHT JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": null, "enrollment.course": "Biology" }), - expect.objectContaining({ "student.name": "John", "enrollment.course": "Mathematics" }) - ])); - expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "John" }), - expect.objectContaining({ "enrollment.course": "Physics", "student.name": "John" }) - ])); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "student.name": "John", "enrollment.course": "Physics" }) - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Mathematics", "student.name": "Bob" }), - expect.objectContaining({ "enrollment.course": "Biology", "student.name": null }) - ])); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await executeSELECTQuery(query); - expect(result).toEqual(expect.arrayContaining([ - expect.objectContaining({ "enrollment.course": "Chemistry", "student.name": "Jane" }), - ])); - expect(result.length).toEqual(1); -}); - -test('Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; - const result = await executeSELECTQuery(query); - expect(result).toEqual([]); -}); - -test('Execute COUNT Aggregate Query', async () => { - const query = 'SELECT COUNT(*) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'COUNT(*)': 4 }]); -}); - -test('Execute SUM Aggregate Query', async () => { - const query = 'SELECT SUM(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'SUM(age)': 101 }]); -}); - -test('Execute AVG Aggregate Query', async () => { - const query = 'SELECT AVG(age) FROM student'; - const result = await executeSELECTQuery(query); - // Assuming AVG returns a single decimal point value - expect(result).toEqual([{ 'AVG(age)': 25.25 }]); -}); - -test('Execute MIN Aggregate Query', async () => { - const query = 'SELECT MIN(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MIN(age)': 22 }]); -}); - -test('Execute MAX Aggregate Query', async () => { - const query = 'SELECT MAX(age) FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ 'MAX(age)': 30 }]); -}); - -test('Count students per age', async () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '22', 'COUNT(*)': 1 }, - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments per course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 }, - { course: 'Physics', 'COUNT(*)': 1 }, - { course: 'Chemistry', 'COUNT(*)': 1 }, - { course: 'Biology', 'COUNT(*)': 1 } - ]); -}); - - -test('Count courses per student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 }, - { student_id: '2', 'COUNT(*)': 1 }, - { student_id: '3', 'COUNT(*)': 1 }, - { student_id: '5', 'COUNT(*)': 1 } - ]); -}); - -test('Count students within a specific age range', async () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { age: '24', 'COUNT(*)': 1 }, - { age: '25', 'COUNT(*)': 1 }, - { age: '30', 'COUNT(*)': 1 } - ]); -}); - -test('Count enrollments for a specific course', async () => { - const query = 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { course: 'Mathematics', 'COUNT(*)': 2 } - ]); -}); - -test('Count courses for a specific student', async () => { - const query = 'SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([ - { student_id: '1', 'COUNT(*)': 2 } - ]); -}); - -test('Average age of students above a certain age', async () => { - const query = 'SELECT AVG(age) FROM student WHERE age > 22'; - const result = await executeSELECTQuery(query); - const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 - expect(result).toEqual([{ 'AVG(age)': expectedAverage }]); -}); - -test('Parse SQL Query', () => { - const query = 'SELECT id, name FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with WHERE Clause', () => { - const query = 'SELECT id, name FROM student WHERE age = 25'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "25", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with Multiple WHERE Clauses', () => { - const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['id', 'name'], - table: 'student', - whereClauses: [{ - "field": "age", - "operator": "=", - "value": "30", - }, { - "field": "name", - "operator": "=", - "value": "John", - }], - joinCondition: null, - joinTable: null, - joinType: null, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with INNER JOIN', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false + expect(result.length).toEqual(2); + // toHaveProperty is not working here due to dot in the property name + expect(result[0]).toEqual( + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", }) -}); - -test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => { - const query = 'SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [{ field: 'student.age', operator: '>', value: '20' }], - joinTable: 'enrollment', - joinType: "INNER", - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}); - -test('Parse INNER JOIN clause', () => { - const query = 'SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'INNER', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' }, - }); -}); - -test('Parse LEFT JOIN clause', () => { - const query = 'SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'LEFT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Parse RIGHT JOIN clause', () => { - const query = 'SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id'; - const result = parseJoinClause(query); - expect(result).toEqual({ - joinType: 'RIGHT', - joinTable: 'table2', - joinCondition: { left: 'table1.id', right: 'table2.ref_id' } - }); -}); - -test('Returns null for queries without JOIN', () => { - const query = 'SELECT * FROM table1'; - const result = parseJoinClause(query); - expect(result).toEqual( - { - joinType: null, - joinTable: null, - joinCondition: null - } - ); -}); - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'LEFT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse LEFT Join Query Completely', () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id'; - const result = parseSelectQuery(query); - expect(result).toEqual({ - fields: ['student.name', 'enrollment.course'], - table: 'student', - whereClauses: [], - joinType: 'RIGHT', - joinTable: 'enrollment', - joinCondition: { left: 'student.id', right: 'enrollment.student_id' }, - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }) -}) - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "LEFT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table', async () => { - const query = 'SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25'; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table', async () => { - const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; - const result = await parseSelectQuery(query); - expect(result).toEqual({ - "fields": ["student.name", "enrollment.course"], - "joinCondition": { "left": "student.id", "right": "enrollment.student_id" }, - "joinTable": "enrollment", - "joinType": "RIGHT", - "table": "student", - "whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }], - groupByFields: null, - hasAggregateWithoutGroupBy: false, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse COUNT Aggregate Query', () => { - const query = 'SELECT COUNT(*) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - - -test('Parse SUM Aggregate Query', () => { - const query = 'SELECT SUM(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['SUM(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse AVG Aggregate Query', () => { - const query = 'SELECT AVG(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['AVG(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MIN Aggregate Query', () => { - const query = 'SELECT MIN(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['MIN(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse MAX Aggregate Query', () => { - const query = 'SELECT MAX(age) FROM student'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['MAX(age)'], - table: 'student', - whereClauses: [], - groupByFields: null, - hasAggregateWithoutGroupBy: true, - "joinCondition": null, - "joinTable": null, - "joinType": null, - "orderByFields": null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse basic GROUP BY query', () => { - const query = 'SELECT age, COUNT(*) FROM student GROUP BY age'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with WHERE clause', () => { - const query = 'SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['age', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'age', operator: '>', value: '22' }], - groupByFields: ['age'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with multiple fields', () => { - const query = 'SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['student_id', 'course', 'COUNT(*)'], - table: 'enrollment', - whereClauses: [], - groupByFields: ['student_id', 'course'], - joinType: null, - joinTable: null, - joinCondition: null, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false - }); -}); - -test('Parse GROUP BY query with JOIN and WHERE clauses', () => { - const query = 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; - const parsed = parseSelectQuery(query); - expect(parsed).toEqual({ - fields: ['student.name', 'COUNT(*)'], - table: 'student', - whereClauses: [{ field: 'enrollment.course', operator: '=', value: '"Mathematics"' }], - groupByFields: ['student.name'], - joinType: 'INNER', - joinTable: 'enrollment', - joinCondition: { - left: 'student.id', - right: 'enrollment.student_id' - }, - hasAggregateWithoutGroupBy: false, - orderByFields: null, - "limit": null, - isDistinct: false, - }); -}); - -test('Execute SQL Query with ORDER BY', async () => { - const query = 'SELECT name FROM student ORDER BY name ASC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'Alice' }, - { name: 'Bob' }, - { name: 'Jane' }, - { name: 'John' } - ]); -}); - -test('Execute SQL Query with ORDER BY and WHERE', async () => { - const query = 'SELECT name FROM student WHERE age > 24 ORDER BY name DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { name: 'John' }, - { name: 'Jane' }, - ]); -}); -test('Execute SQL Query with ORDER BY and GROUP BY', async () => { - const query = 'SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC'; - const result = await executeSELECTQuery(query); - - expect(result).toStrictEqual([ - { age: '30', 'COUNT(id) as count': 1 }, - { age: '25', 'COUNT(id) as count': 1 }, - { age: '24', 'COUNT(id) as count': 1 }, - { age: '22', 'COUNT(id) as count': 1 } - ]); -}); - -test('Execute SQL Query with standard LIMIT clause', async () => { - const query = 'SELECT id, name FROM student LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); -}); - -test('Execute SQL Query with LIMIT clause equal to total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 4'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); -}); - -test('Execute SQL Query with LIMIT clause exceeding total rows', async () => { - const query = 'SELECT id, name FROM student LIMIT 10'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(4); // Total rows in student.csv -}); - -test('Execute SQL Query with LIMIT 0', async () => { - const query = 'SELECT id, name FROM student LIMIT 0'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(0); -}); - -test('Execute SQL Query with LIMIT and ORDER BY clause', async () => { - const query = 'SELECT id, name FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - expect(result.length).toEqual(2); - expect(result[0].name).toEqual('John'); - expect(result[1].name).toEqual('Jane'); -}); - -test('Error Handling with Malformed Query', async () => { - const query = 'SELECT FROM table'; // intentionally malformed - await expect(executeSELECTQuery(query)).rejects.toThrow("Error executing query: Query parsing error: Invalid SELECT format"); -}); - -test('Basic DISTINCT Usage', async () => { - const query = 'SELECT DISTINCT age FROM student'; - const result = await executeSELECTQuery(query); - expect(result).toEqual([{ age: '30' }, { age: '25' }, { age: '22' }, { age: '24' }]); -}); - -test('DISTINCT with Multiple Columns', async () => { - const query = 'SELECT DISTINCT student_id, course FROM enrollment'; - const result = await executeSELECTQuery(query); - // Expecting unique combinations of student_id and course - expect(result).toEqual([ - { student_id: '1', course: 'Mathematics' }, - { student_id: '1', course: 'Physics' }, - { student_id: '2', course: 'Chemistry' }, - { student_id: '3', course: 'Mathematics' }, - { student_id: '5', course: 'Biology' }, - ]); + ); +}); + +test("Execute SQL Query with LEFT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "Alice", + "enrollment.course": null, + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 students, but John appears twice +}); + +test("Execute SQL Query with RIGHT JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": null, + "enrollment.course": "Biology", + }), + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Mathematics", + }), + ]) + ); + expect(result.length).toEqual(5); // 4 courses, but Mathematics appears twice +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "John", + }), + expect.objectContaining({ + "enrollment.course": "Physics", + "student.name": "John", + }), + ]) + ); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "student.name": "John", + "enrollment.course": "Physics", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Mathematics", + "student.name": "Bob", + }), + expect.objectContaining({ + "enrollment.course": "Biology", + "student.name": null, + }), + ]) + ); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await executeSELECTQuery(query); + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + "enrollment.course": "Chemistry", + "student.name": "Jane", + }), + ]) + ); + expect(result.length).toEqual(1); +}); + +test("Execute SQL Query with RIGHT JOIN with a multiple WHERE clauses filtering the join table and main table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry' AND student.age = 26`; + const result = await executeSELECTQuery(query); + expect(result).toEqual([]); +}); + +test("Execute COUNT Aggregate Query", async () => { + const query = "SELECT COUNT(*) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "COUNT(*)": 4 }]); +}); + +test("Execute SUM Aggregate Query", async () => { + const query = "SELECT SUM(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "SUM(age)": 101 }]); +}); + +test("Execute AVG Aggregate Query", async () => { + const query = "SELECT AVG(age) FROM student"; + const result = await executeSELECTQuery(query); + // Assuming AVG returns a single decimal point value + expect(result).toEqual([{ "AVG(age)": 25.25 }]); +}); + +test("Execute MIN Aggregate Query", async () => { + const query = "SELECT MIN(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MIN(age)": 22 }]); +}); + +test("Execute MAX Aggregate Query", async () => { + const query = "SELECT MAX(age) FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ "MAX(age)": 30 }]); +}); + +test("Count students per age", async () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "22", "COUNT(*)": 1 }, + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments per course", async () => { + const query = "SELECT course, COUNT(*) FROM enrollment GROUP BY course"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { course: "Mathematics", "COUNT(*)": 2 }, + { course: "Physics", "COUNT(*)": 1 }, + { course: "Chemistry", "COUNT(*)": 1 }, + { course: "Biology", "COUNT(*)": 1 }, + ]); +}); + +test("Count courses per student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { student_id: "1", "COUNT(*)": 2 }, + { student_id: "2", "COUNT(*)": 1 }, + { student_id: "3", "COUNT(*)": 1 }, + { student_id: "5", "COUNT(*)": 1 }, + ]); +}); + +test("Count students within a specific age range", async () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "24", "COUNT(*)": 1 }, + { age: "25", "COUNT(*)": 1 }, + { age: "30", "COUNT(*)": 1 }, + ]); +}); + +test("Count enrollments for a specific course", async () => { + const query = + 'SELECT course, COUNT(*) FROM enrollment WHERE course = "Mathematics" GROUP BY course'; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ course: "Mathematics", "COUNT(*)": 2 }]); +}); + +test("Count courses for a specific student", async () => { + const query = + "SELECT student_id, COUNT(*) FROM enrollment WHERE student_id = 1 GROUP BY student_id"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([{ student_id: "1", "COUNT(*)": 2 }]); +}); + +test("Average age of students above a certain age", async () => { + const query = "SELECT AVG(age) FROM student WHERE age > 22"; + const result = await executeSELECTQuery(query); + const expectedAverage = (25 + 30 + 24) / 3; // Average age of students older than 22 + expect(result).toEqual([{ "AVG(age)": expectedAverage }]); +}); + +test("Parse SQL Query", () => { + const query = "SELECT id, name FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with WHERE Clause", () => { + const query = "SELECT id, name FROM student WHERE age = 25"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "25", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with Multiple WHERE Clauses", () => { + const query = "SELECT id, name FROM student WHERE age = 30 AND name = John"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["id", "name"], + table: "student", + whereClauses: [ + { + field: "age", + operator: "=", + value: "30", + }, + { + field: "name", + operator: "=", + value: "John", + }, + ], + joinCondition: null, + joinTable: null, + joinType: null, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id=enrollment.student_id"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with INNER JOIN and WHERE Clause", async () => { + const query = + "SELECT student.name, enrollment.course FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE student.age > 20"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "20" }], + joinTable: "enrollment", + joinType: "INNER", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse INNER JOIN clause", () => { + const query = + "SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "INNER", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse LEFT JOIN clause", () => { + const query = + "SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "LEFT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Parse RIGHT JOIN clause", () => { + const query = + "SELECT * FROM table1 RIGHT JOIN table2 ON table1.id = table2.ref_id"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: "RIGHT", + joinTable: "table2", + joinCondition: { left: "table1.id", right: "table2.ref_id" }, + }); +}); + +test("Returns null for queries without JOIN", () => { + const query = "SELECT * FROM table1"; + const result = parseJoinClause(query); + expect(result).toEqual({ + joinType: null, + joinTable: null, + joinCondition: null, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "LEFT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse LEFT Join Query Completely", () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id"; + const result = parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + table: "student", + whereClauses: [], + joinType: "RIGHT", + joinTable: "enrollment", + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age > 22"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [{ field: "student.age", operator: ">", value: "22" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student LEFT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Physics'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "LEFT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Physics'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main table", async () => { + const query = + "SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE student.age < 25"; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [{ field: "student.age", operator: "<", value: "25" }], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join table", async () => { + const query = `SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`; + const result = await parseSelectQuery(query); + expect(result).toEqual({ + fields: ["student.name", "enrollment.course"], + joinCondition: { left: "student.id", right: "enrollment.student_id" }, + joinTable: "enrollment", + joinType: "RIGHT", + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: "'Chemistry'" }, + ], + groupByFields: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse COUNT Aggregate Query", () => { + const query = "SELECT COUNT(*) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse SUM Aggregate Query", () => { + const query = "SELECT SUM(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["SUM(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse AVG Aggregate Query", () => { + const query = "SELECT AVG(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["AVG(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MIN Aggregate Query", () => { + const query = "SELECT MIN(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MIN(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse MAX Aggregate Query", () => { + const query = "SELECT MAX(age) FROM student"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["MAX(age)"], + table: "student", + whereClauses: [], + groupByFields: null, + hasAggregateWithoutGroupBy: true, + joinCondition: null, + joinTable: null, + joinType: null, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse basic GROUP BY query", () => { + const query = "SELECT age, COUNT(*) FROM student GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with WHERE clause", () => { + const query = "SELECT age, COUNT(*) FROM student WHERE age > 22 GROUP BY age"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["age", "COUNT(*)"], + table: "student", + whereClauses: [{ field: "age", operator: ">", value: "22" }], + groupByFields: ["age"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with multiple fields", () => { + const query = + "SELECT student_id, course, COUNT(*) FROM enrollment GROUP BY student_id, course"; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student_id", "course", "COUNT(*)"], + table: "enrollment", + whereClauses: [], + groupByFields: ["student_id", "course"], + joinType: null, + joinTable: null, + joinCondition: null, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Parse GROUP BY query with JOIN and WHERE clauses", () => { + const query = + 'SELECT student.name, COUNT(*) FROM student INNER JOIN enrollment ON student.id = enrollment.student_id WHERE enrollment.course = "Mathematics" GROUP BY student.name'; + const parsed = parseSelectQuery(query); + expect(parsed).toEqual({ + fields: ["student.name", "COUNT(*)"], + table: "student", + whereClauses: [ + { field: "enrollment.course", operator: "=", value: '"Mathematics"' }, + ], + groupByFields: ["student.name"], + joinType: "INNER", + joinTable: "enrollment", + joinCondition: { + left: "student.id", + right: "enrollment.student_id", + }, + hasAggregateWithoutGroupBy: false, + orderByFields: null, + limit: null, + isDistinct: false, + }); +}); + +test("Execute SQL Query with ORDER BY", async () => { + const query = "SELECT name FROM student ORDER BY name ASC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { name: "Alice" }, + { name: "Bob" }, + { name: "Jane" }, + { name: "John" }, + ]); +}); + +test("Execute SQL Query with ORDER BY and WHERE", async () => { + const query = "SELECT name FROM student WHERE age > 24 ORDER BY name DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([{ name: "John" }, { name: "Jane" }]); +}); +test("Execute SQL Query with ORDER BY and GROUP BY", async () => { + const query = + "SELECT COUNT(id) as count, age FROM student GROUP BY age ORDER BY age DESC"; + const result = await executeSELECTQuery(query); + + expect(result).toStrictEqual([ + { age: "30", "COUNT(id) as count": 1 }, + { age: "25", "COUNT(id) as count": 1 }, + { age: "24", "COUNT(id) as count": 1 }, + { age: "22", "COUNT(id) as count": 1 }, + ]); +}); + +test("Execute SQL Query with standard LIMIT clause", async () => { + const query = "SELECT id, name FROM student LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); +}); + +test("Execute SQL Query with LIMIT clause equal to total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 4"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); +}); + +test("Execute SQL Query with LIMIT clause exceeding total rows", async () => { + const query = "SELECT id, name FROM student LIMIT 10"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(4); // Total rows in student.csv +}); + +test("Execute SQL Query with LIMIT 0", async () => { + const query = "SELECT id, name FROM student LIMIT 0"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(0); +}); + +test("Execute SQL Query with LIMIT and ORDER BY clause", async () => { + const query = "SELECT id, name FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + expect(result.length).toEqual(2); + expect(result[0].name).toEqual("John"); + expect(result[1].name).toEqual("Jane"); +}); + +test("Error Handling with Malformed Query", async () => { + const query = "SELECT FROM table"; // intentionally malformed + await expect(executeSELECTQuery(query)).rejects.toThrow( + "Error executing query: Query parsing error: Invalid SELECT format" + ); +}); + +test("Basic DISTINCT Usage", async () => { + const query = "SELECT DISTINCT age FROM student"; + const result = await executeSELECTQuery(query); + expect(result).toEqual([ + { age: "30" }, + { age: "25" }, + { age: "22" }, + { age: "24" }, + ]); +}); + +test("DISTINCT with Multiple Columns", async () => { + const query = "SELECT DISTINCT student_id, course FROM enrollment"; + const result = await executeSELECTQuery(query); + // Expecting unique combinations of student_id and course + expect(result).toEqual([ + { student_id: "1", course: "Mathematics" }, + { student_id: "1", course: "Physics" }, + { student_id: "2", course: "Chemistry" }, + { student_id: "3", course: "Mathematics" }, + { student_id: "5", course: "Biology" }, + ]); }); // Not a good test right now -test('DISTINCT with WHERE Clause', async () => { - const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; - const result = await executeSELECTQuery(query); - // Expecting courses taken by student with ID 1 - expect(result).toEqual([{ course: 'Mathematics' }, { course: 'Physics' }]); +test("DISTINCT with WHERE Clause", async () => { + const query = 'SELECT DISTINCT course FROM enrollment WHERE student_id = "1"'; + const result = await executeSELECTQuery(query); + // Expecting courses taken by student with ID 1 + expect(result).toEqual([{ course: "Mathematics" }, { course: "Physics" }]); }); -test('DISTINCT with JOIN Operations', async () => { - const query = 'SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id'; - const result = await executeSELECTQuery(query); - // Expecting names of students who are enrolled in any course - expect(result).toEqual([{ "student.name": 'John' }, { "student.name": 'Jane' }, { "student.name": 'Bob' }]); +test("DISTINCT with JOIN Operations", async () => { + const query = + "SELECT DISTINCT student.name FROM student INNER JOIN enrollment ON student.id = enrollment.student_id"; + const result = await executeSELECTQuery(query); + // Expecting names of students who are enrolled in any course + expect(result).toEqual([ + { "student.name": "John" }, + { "student.name": "Jane" }, + { "student.name": "Bob" }, + ]); }); -test('DISTINCT with ORDER BY and LIMIT', async () => { - const query = 'SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2'; - const result = await executeSELECTQuery(query); - // Expecting the two highest unique ages - expect(result).toEqual([{ age: '30' }, { age: '25' }]); +test("DISTINCT with ORDER BY and LIMIT", async () => { + const query = "SELECT DISTINCT age FROM student ORDER BY age DESC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the two highest unique ages + expect(result).toEqual([{ age: "30" }, { age: "25" }]); }); -test('Execute SQL Query with LIKE Operator for Name', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; - const result = await executeSELECTQuery(query); - // Expecting names containing 'Jane' - expect(result).toEqual([{ name: 'Jane' }]); +test("Execute SQL Query with LIKE Operator for Name", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%Jane%'"; + const result = await executeSELECTQuery(query); + // Expecting names containing 'Jane' + expect(result).toEqual([{ name: "Jane" }]); }); -test('Execute SQL Query with LIKE Operator and Wildcards', async () => { - const query = "SELECT name FROM student WHERE name LIKE 'J%'"; - const result = await executeSELECTQuery(query); - // Expecting names starting with 'J' - expect(result).toEqual([{ name: 'John' }, { name: 'Jane' }]); +test("Execute SQL Query with LIKE Operator and Wildcards", async () => { + const query = "SELECT name FROM student WHERE name LIKE 'J%'"; + const result = await executeSELECTQuery(query); + // Expecting names starting with 'J' + expect(result).toEqual([{ name: "John" }, { name: "Jane" }]); }); -test('Execute SQL Query with LIKE Operator Case Insensitive', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%bob%'"; - const result = await executeSELECTQuery(query); - // Expecting names 'Bob' (case insensitive) - expect(result).toEqual([{ name: 'Bob' }]); +test("Execute SQL Query with LIKE Operator Case Insensitive", async () => { + const query = "SELECT name FROM student WHERE name LIKE '%bob%'"; + const result = await executeSELECTQuery(query); + // Expecting names 'Bob' (case insensitive) + expect(result).toEqual([{ name: "Bob" }]); }); -test('Execute SQL Query with LIKE Operator and DISTINCT', async () => { - const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%'"; - const result = await executeSELECTQuery(query); - // Expecting unique names containing 'e' - expect(result).toEqual([{ name: 'Jane' }, { name: 'Alice' }]); +test("Execute SQL Query with LIKE Operator and DISTINCT", async () => { + const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%'"; + const result = await executeSELECTQuery(query); + // Expecting unique names containing 'e' + expect(result).toEqual([{ name: "Jane" }, { name: "Alice" }]); }); -test('LIKE with ORDER BY and LIMIT', async () => { - const query = "SELECT name FROM student WHERE name LIKE '%a%' ORDER BY name ASC LIMIT 2"; - const result = await executeSELECTQuery(query); - // Expecting the first two names alphabetically that contain 'a' - expect(result).toEqual([{ name: 'Alice' }, { name: 'Jane' }]); -}); \ No newline at end of file +test("LIKE with ORDER BY and LIMIT", async () => { + const query = + "SELECT name FROM student WHERE name LIKE '%a%' ORDER BY name ASC LIMIT 2"; + const result = await executeSELECTQuery(query); + // Expecting the first two names alphabetically that contain 'a' + expect(result).toEqual([{ name: "Alice" }, { name: "Jane" }]); +}); diff --git a/tests/step-19/insertExecuter.test.js b/tests/step-19/insertExecuter.test.js index 8c405f727..473314045 100644 --- a/tests/step-19/insertExecuter.test.js +++ b/tests/step-19/insertExecuter.test.js @@ -1,33 +1,36 @@ -const { executeINSERTQuery } = require('../../src/index'); -const { readCSV, writeCSV } = require('../../src/csvReader'); -const fs = require('fs'); +const { executeINSERTQuery } = require("../../src/queryExecutor"); +const { readCSV, writeCSV } = require("../../src/csvReader"); +const fs = require("fs"); // Helper function to create grades.csv with initial data async function createGradesCSV() { - const initialData = [ - { student_id: '1', course: 'Mathematics', grade: 'A' }, - { student_id: '2', course: 'Chemistry', grade: 'B' }, - { student_id: '3', course: 'Mathematics', grade: 'C' } - ]; - await writeCSV('grades.csv', initialData); + const initialData = [ + { student_id: "1", course: "Mathematics", grade: "A" }, + { student_id: "2", course: "Chemistry", grade: "B" }, + { student_id: "3", course: "Mathematics", grade: "C" }, + ]; + await writeCSV("grades.csv", initialData); } // Test to INSERT a new grade and verify -test('Execute INSERT INTO Query for grades.csv', async () => { - // Create grades.csv with initial data - await createGradesCSV(); +test("Execute INSERT INTO Query for grades.csv", async () => { + // Create grades.csv with initial data + await createGradesCSV(); - // Execute INSERT statement - const insertQuery = "INSERT INTO grades (student_id, course, grade) VALUES ('4', 'Physics', 'A')"; - await executeINSERTQuery(insertQuery); + // Execute INSERT statement + const insertQuery = + "INSERT INTO grades (student_id, course, grade) VALUES ('4', 'Physics', 'A')"; + await executeINSERTQuery(insertQuery); - // Verify the new entry - const updatedData = await readCSV('grades.csv'); - const newEntry = updatedData.find(row => row.student_id === '4' && row.course === 'Physics'); - console.log(updatedData) - expect(newEntry).toBeDefined(); - expect(newEntry.grade).toEqual('A'); + // Verify the new entry + const updatedData = await readCSV("grades.csv"); + const newEntry = updatedData.find( + (row) => row.student_id === "4" && row.course === "Physics" + ); - // Cleanup: Delete grades.csv - fs.unlinkSync('grades.csv'); -}); \ No newline at end of file + expect(newEntry).toBeDefined(); + expect(newEntry.grade).toEqual("A"); + + // Cleanup: Delete grades.csv + fs.unlinkSync("grades.csv"); +}); diff --git a/util/generateLargeFile.js b/util/generateLargeFile.js new file mode 100644 index 000000000..279a44441 --- /dev/null +++ b/util/generateLargeFile.js @@ -0,0 +1,34 @@ +const fs = require("fs"); +const { faker, da } = require("@faker-js/faker"); +const { parse } = require("json2csv"); + +async function generateLargeCSV(filename) { + let data = []; + for (let i = 1; i <= 10_000_000; i++) { + const record = { + id: i, + name: faker.person.firstName(), + age: faker.number.int({ min: 18, max: 100 }), + }; + data.push(record); + + let rows; + if (i % 500_000 === 0) { + console.log(`Generated ${i} records`); + if (!fs.existsSync(filename)) { + rows = parse(data, { header: true }); + } else { + // Rows without headers. + rows = parse(data, { header: false }); + } + fs.appendFileSync(filename, rows); + data = []; + } + } + // Append file function can create new file too. + + // Always add new line if file already exists. + fs.appendFileSync(filename, "\r\n"); +} + +generateLargeCSV("student_large.csv");