From c9a9cd27a29f3f976345e9506e78861b2a2c51a5 Mon Sep 17 00:00:00 2001
From: "github-classroom[bot]"
<66690702+github-classroom[bot]@users.noreply.github.com>
Date: Thu, 11 Apr 2024 17:32:41 +0000
Subject: [PATCH 01/14] Update GitHub Classroom Autograding Workflow
---
.github/workflows/classroom.yml | 223 ++++++++++++++++++++++++++++++--
1 file changed, 212 insertions(+), 11 deletions(-)
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
From 30a06715183570691bdb4a8ec13685cac57ea0e2 Mon Sep 17 00:00:00 2001
From: "github-classroom[bot]"
<66690702+github-classroom[bot]@users.noreply.github.com>
Date: Thu, 11 Apr 2024 17:32:42 +0000
Subject: [PATCH 02/14] GitHub Classroom Feedback
---
.github/.keep | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 .github/.keep
diff --git a/.github/.keep b/.github/.keep
new file mode 100644
index 000000000..e69de29bb
From 9f36408ccccc757dd8ef87707583230543ba122c Mon Sep 17 00:00:00 2001
From: "github-classroom[bot]"
<66690702+github-classroom[bot]@users.noreply.github.com>
Date: Thu, 11 Apr 2024 17:32:42 +0000
Subject: [PATCH 03/14] Setting up GitHub Classroom Feedback
From b85795e72dcc7a084546a36381f83cde5a0effef Mon Sep 17 00:00:00 2001
From: "github-classroom[bot]"
<66690702+github-classroom[bot]@users.noreply.github.com>
Date: Thu, 11 Apr 2024 17:32:44 +0000
Subject: [PATCH 04/14] add online IDE url
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index eadfc715a..311a4386e 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+[](https://classroom.github.com/online_ide?assignment_repo_id=14702203&assignment_repo_type=AssignmentRepo)
StylusDB SQL
A SQL database engine written in JavaScript
From 02a1d85e17c0fa23fba54367cc12791f79da1194 Mon Sep 17 00:00:00 2001
From: sparking_chips
Date: Sat, 13 Apr 2024 13:03:55 +0530
Subject: [PATCH 05/14] step 1, 2 and 3 done
---
src/csvReader.js | 22 ++++++++++++++++++++++
src/index.js | 0
src/queryParser.js | 18 ++++++++++++++++++
3 files changed, 40 insertions(+)
create mode 100644 src/index.js
create mode 100644 src/queryParser.js
diff --git a/src/csvReader.js b/src/csvReader.js
index e69de29bb..0f5a57045 100644
--- a/src/csvReader.js
+++ b/src/csvReader.js
@@ -0,0 +1,22 @@
+// 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);
+ });
+ });
+}
+
+module.exports = readCSV;
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/queryParser.js b/src/queryParser.js
new file mode 100644
index 000000000..1bbac7032
--- /dev/null
+++ b/src/queryParser.js
@@ -0,0 +1,18 @@
+// src/queryParser.js
+
+function parseQuery(query) {
+ const selectRegex = /SELECT (.+) FROM (.+)/i;
+ const match = query.match(selectRegex);
+
+ if (match) {
+ const [, fields, table] = match;
+ return {
+ fields: fields.split(',').map(field => field.trim()),
+ table: table.trim()
+ };
+ } else {
+ throw new Error('Invalid query format');
+ }
+}
+
+module.exports = parseQuery;
From a93c0a484d948d7cf855873aa6151384cfab251b Mon Sep 17 00:00:00 2001
From: sparking_chips
Date: Sat, 13 Apr 2024 14:59:17 +0530
Subject: [PATCH 06/14] step3 completed
---
src/csvReader.js | 22 ++++++++++++++++++++++
src/index.js | 0
src/queryParser.js | 18 ++++++++++++++++++
3 files changed, 40 insertions(+)
create mode 100644 src/index.js
create mode 100644 src/queryParser.js
diff --git a/src/csvReader.js b/src/csvReader.js
index e69de29bb..0b7b54548 100644
--- a/src/csvReader.js
+++ b/src/csvReader.js
@@ -0,0 +1,22 @@
+// 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);
+ });
+ });
+}
+
+module.exports = readCSV;
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/queryParser.js b/src/queryParser.js
new file mode 100644
index 000000000..d3ad6038f
--- /dev/null
+++ b/src/queryParser.js
@@ -0,0 +1,18 @@
+// src/queryParser.js
+
+function parseQuery(query) {
+ const selectRegex = /SELECT (.+) FROM (.+)/i;
+ const match = query.match(selectRegex);
+
+ if (match) {
+ const [, fields, table] = match;
+ return {
+ fields: fields.split(',').map(field => field.trim()),
+ table: table.trim()
+ };
+ } else {
+ throw new Error('Invalid query format');
+ }
+}
+
+module.exports = parseQuery;
\ No newline at end of file
From 4139dbeee7d10f5f829f7d29d565643a70e8e5c1 Mon Sep 17 00:00:00 2001
From: sparking_chips
Date: Sat, 13 Apr 2024 21:15:48 +0530
Subject: [PATCH 07/14] task 1 to 5 completed
---
src/index.js | 28 ++++++++++++++++++++++++++++
src/queryParser.js | 7 ++++---
tests/index.test.js | 27 +++++++++++++++++++++++++++
tests/step-03/index.test.js | 3 ++-
tests/step-04/index.test.js | 3 ++-
5 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/src/index.js b/src/index.js
index e69de29bb..5eb73c3f9 100644
--- a/src/index.js
+++ b/src/index.js
@@ -0,0 +1,28 @@
+// src/index.js
+
+const parseQuery = require('./queryParser');
+const readCSV = require('./csvReader');
+
+async function executeSELECTQuery(query) {
+ const { fields, table, whereClause } = parseQuery(query);
+ const data = await readCSV(`${table}.csv`);
+
+ // Filtering based on WHERE clause
+ const filteredData = whereClause
+ ? data.filter(row => {
+ const [field, value] = whereClause.split('=').map(s => s.trim());
+ return row[field] === value;
+ })
+ : data;
+
+ // Selecting the specified fields
+ return filteredData.map(row => {
+ const selectedRow = {};
+ fields.forEach(field => {
+ selectedRow[field] = row[field];
+ });
+ return selectedRow;
+ });
+}
+
+module.exports = executeSELECTQuery;
\ No newline at end of file
diff --git a/src/queryParser.js b/src/queryParser.js
index d3ad6038f..a7a27174d 100644
--- a/src/queryParser.js
+++ b/src/queryParser.js
@@ -1,14 +1,15 @@
// src/queryParser.js
function parseQuery(query) {
- const selectRegex = /SELECT (.+) FROM (.+)/i;
+ const selectRegex = /SELECT (.+?) FROM (.+?)(?: WHERE (.*))?$/i;
const match = query.match(selectRegex);
if (match) {
- const [, fields, table] = match;
+ const [, fields, table, whereClause] = match;
return {
fields: fields.split(',').map(field => field.trim()),
- table: table.trim()
+ table: table.trim(),
+ whereClause: whereClause ? whereClause.trim() : null
};
} else {
throw new Error('Invalid query format');
diff --git a/tests/index.test.js b/tests/index.test.js
index 61eb2cf85..3a33b1b28 100644
--- a/tests/index.test.js
+++ b/tests/index.test.js
@@ -27,4 +27,31 @@ test('Parse SQL Query', () => {
fields: ['id', 'name'],
table: 'sample'
});
+});
+
+// tests/index.test.js
+
+const executeSELECTQuery = require('../src/index');
+
+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' });
+});
+
+// tests/index.test.js
+
+const executeSELECTQuery = require('../src/index');
+
+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
diff --git a/tests/step-03/index.test.js b/tests/step-03/index.test.js
index 9145ad3e4..77ed7c241 100644
--- a/tests/step-03/index.test.js
+++ b/tests/step-03/index.test.js
@@ -14,6 +14,7 @@ test('Parse SQL Query', () => {
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample'
+ table: 'sample',
+ whereClause: null
});
});
\ No newline at end of file
diff --git a/tests/step-04/index.test.js b/tests/step-04/index.test.js
index bc353dd3d..e96c8d14a 100644
--- a/tests/step-04/index.test.js
+++ b/tests/step-04/index.test.js
@@ -15,7 +15,8 @@ test('Parse SQL Query', () => {
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample'
+ table: 'sample',
+ whereClause: null
});
});
From 52e3d08872153bd92f96d2c698b3a4402c15edd8 Mon Sep 17 00:00:00 2001
From: sparking_chips
Date: Sun, 14 Apr 2024 02:16:04 +0530
Subject: [PATCH 08/14] completed till step 7
---
src/index.js | 29 ++++++++++++++++++---------
src/queryParser.js | 18 +++++++++++++++--
tests/index.test.js | 40 +++++++++++++++++++++++++++++++++++++
tests/step-03/index.test.js | 2 +-
tests/step-04/index.test.js | 2 +-
tests/step-05/index.test.js | 9 +++++++--
6 files changed, 85 insertions(+), 15 deletions(-)
diff --git a/src/index.js b/src/index.js
index 5eb73c3f9..112ae8231 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,19 +3,30 @@
const parseQuery = require('./queryParser');
const readCSV = require('./csvReader');
+// src/index.js
+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}`);
+ }
+}
+
async function executeSELECTQuery(query) {
- const { fields, table, whereClause } = parseQuery(query);
+ const { fields, table, whereClauses } = parseQuery(query);
const data = await readCSV(`${table}.csv`);
-
- // Filtering based on WHERE clause
- const filteredData = whereClause
- ? data.filter(row => {
- const [field, value] = whereClause.split('=').map(s => s.trim());
- return row[field] === value;
- })
+
+ // Apply WHERE clause filtering
+ const filteredData = whereClauses.length > 0
+ ? data.filter(row => whereClauses.every(clause => evaluateCondition(row, clause)))
: data;
- // Selecting the specified fields
+ // Select the specified fields
return filteredData.map(row => {
const selectedRow = {};
fields.forEach(field => {
diff --git a/src/queryParser.js b/src/queryParser.js
index a7a27174d..9b34f2f5e 100644
--- a/src/queryParser.js
+++ b/src/queryParser.js
@@ -5,15 +5,29 @@ function parseQuery(query) {
const match = query.match(selectRegex);
if (match) {
- const [, fields, table, whereClause] = match;
+ const [, fields, table, whereString] = match;
+ const whereClauses = whereString ? parseWhereClause(whereString) : [];
return {
fields: fields.split(',').map(field => field.trim()),
table: table.trim(),
- whereClause: whereClause ? whereClause.trim() : null
+ whereClauses
};
} else {
throw new Error('Invalid query format');
}
}
+// src/queryParser.js
+function parseWhereClause(whereString) {
+ const conditionRegex = /(.*?)(=|!=|>|<|>=|<=)(.*)/;
+ return whereString.split(/ AND | OR /i).map(conditionString => {
+ const match = conditionString.match(conditionRegex);
+ if (match) {
+ const [, field, operator, value] = match;
+ return { field: field.trim(), operator, value: value.trim() };
+ }
+ throw new Error('Invalid WHERE clause format');
+ });
+}
+
module.exports = parseQuery;
\ No newline at end of file
diff --git a/tests/index.test.js b/tests/index.test.js
index 3a33b1b28..8b2d4867f 100644
--- a/tests/index.test.js
+++ b/tests/index.test.js
@@ -54,4 +54,44 @@ test('Execute SQL Query with WHERE Clause', async () => {
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('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' });
+});
+
+// tests/index.test.js
+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 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
diff --git a/tests/step-03/index.test.js b/tests/step-03/index.test.js
index 77ed7c241..d5822faf9 100644
--- a/tests/step-03/index.test.js
+++ b/tests/step-03/index.test.js
@@ -15,6 +15,6 @@ test('Parse SQL Query', () => {
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'sample',
- whereClause: null
+ whereClauses:[]
});
});
\ No newline at end of file
diff --git a/tests/step-04/index.test.js b/tests/step-04/index.test.js
index e96c8d14a..6c104d895 100644
--- a/tests/step-04/index.test.js
+++ b/tests/step-04/index.test.js
@@ -16,7 +16,7 @@ test('Parse SQL Query', () => {
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'sample',
- whereClause: null
+ whereClauses: []
});
});
diff --git a/tests/step-05/index.test.js b/tests/step-05/index.test.js
index 66a77c061..37be0d154 100644
--- a/tests/step-05/index.test.js
+++ b/tests/step-05/index.test.js
@@ -16,7 +16,7 @@ test('Parse SQL Query', () => {
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'sample',
- whereClause: null
+ whereClauses: []
});
});
@@ -36,7 +36,12 @@ test('Parse SQL Query with WHERE Clause', () => {
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'sample',
- whereClause: 'age = 25'
+ whereClauses: [{
+ "field":"age",
+ "operator":"=",
+ "value":"25"
+ }
+ ]
});
});
From 75b34c077c4591e5d83a946a7e351f9b900cb604 Mon Sep 17 00:00:00 2001
From: sparking_chips
Date: Sun, 14 Apr 2024 02:43:59 +0530
Subject: [PATCH 09/14] completed till task 8
---
enrollment.csv | 5 +++
src/index.js | 24 +++++++++++--
src/queryParser.js | 70 ++++++++++++++++++++++++++++++-------
sample.csv => student.csv | 0
tests/index.test.js | 27 ++++++++------
tests/step-02/index.test.js | 2 +-
tests/step-03/index.test.js | 10 +++---
tests/step-04/index.test.js | 12 ++++---
tests/step-05/index.test.js | 23 +++++++-----
tests/step-06/index.test.js | 26 ++++++++------
tests/step-07/index.test.js | 30 +++++++++-------
11 files changed, 162 insertions(+), 67 deletions(-)
create mode 100644 enrollment.csv
rename sample.csv => student.csv (100%)
diff --git a/enrollment.csv b/enrollment.csv
new file mode 100644
index 000000000..779ff5501
--- /dev/null
+++ b/enrollment.csv
@@ -0,0 +1,5 @@
+student_id,course
+1,Mathematics
+1,Physics
+2,Chemistry
+3,Mathematics
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 112ae8231..8cfaca985 100644
--- a/src/index.js
+++ b/src/index.js
@@ -18,8 +18,28 @@ function evaluateCondition(row, clause) {
}
async function executeSELECTQuery(query) {
- const { fields, table, whereClauses } = parseQuery(query);
- const data = await readCSV(`${table}.csv`);
+ const { fields, table, whereClauses, joinTable, joinCondition } = parseQuery(query);
+ let data = await readCSV(`${table}.csv`);
+
+ // Perform INNER JOIN if specified
+ if (joinTable && joinCondition) {
+ const joinData = await readCSV(`${joinTable}.csv`);
+ 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;
+ }, {});
+ });
+ });
+ }
// Apply WHERE clause filtering
const filteredData = whereClauses.length > 0
diff --git a/src/queryParser.js b/src/queryParser.js
index 9b34f2f5e..0222adae1 100644
--- a/src/queryParser.js
+++ b/src/queryParser.js
@@ -1,20 +1,65 @@
// src/queryParser.js
+
function parseQuery(query) {
- const selectRegex = /SELECT (.+?) FROM (.+?)(?: WHERE (.*))?$/i;
- const match = query.match(selectRegex);
-
- if (match) {
- const [, fields, table, whereString] = match;
- const whereClauses = whereString ? parseWhereClause(whereString) : [];
- return {
- fields: fields.split(',').map(field => field.trim()),
- table: table.trim(),
- whereClauses
+ // First, let's trim the query to remove any leading/trailing whitespaces
+ query = query.trim();
+
+ // 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(/\sINNER JOIN\s/i);
+ selectPart = joinSplit[0].trim(); // Everything before JOIN clause
+
+ // JOIN clause is the second part after splitting, if it exists
+ const joinPart = joinSplit.length > 1 ? joinSplit[1].trim() : null;
+
+ // 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
+ let joinTable = null, joinCondition = null;
+ if (joinPart) {
+ const joinRegex = /^(.+?)\sON\s([\w.]+)\s*=\s*([\w.]+)/i;
+ const joinMatch = joinPart.match(joinRegex);
+ if (!joinMatch) {
+ throw new Error('Invalid JOIN format');
+ }
+
+ joinTable = joinMatch[1].trim();
+ joinCondition = {
+ left: joinMatch[2].trim(),
+ right: joinMatch[3].trim()
};
- } else {
- throw new Error('Invalid query format');
}
+
+ // 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,
+ joinTable,
+ joinCondition
+ };
}
// src/queryParser.js
@@ -29,5 +74,4 @@ function parseWhereClause(whereString) {
throw new Error('Invalid WHERE clause format');
});
}
-
module.exports = parseQuery;
\ No newline at end of file
diff --git a/sample.csv b/student.csv
similarity index 100%
rename from sample.csv
rename to student.csv
diff --git a/tests/index.test.js b/tests/index.test.js
index 8b2d4867f..793600153 100644
--- a/tests/index.test.js
+++ b/tests/index.test.js
@@ -9,7 +9,7 @@ test('Basic Jest Test', () => {
const readCSV = require('../src/csvReader');
test('Read CSV File', async () => {
- const data = await readCSV('./sample.csv');
+ const data = await readCSV('./student.csv');
expect(data.length).toBeGreaterThan(0);
expect(data.length).toBe(3);
expect(data[0].name).toBe('John');
@@ -21,11 +21,11 @@ test('Read CSV File', async () => {
const parseQuery = require('../src/queryParser');
test('Parse SQL Query', () => {
- const query = 'SELECT id, name FROM sample';
+ const query = 'SELECT id, name FROM student';
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample'
+ table: 'student'
});
});
@@ -34,7 +34,7 @@ test('Parse SQL Query', () => {
const executeSELECTQuery = require('../src/index');
test('Execute SQL Query', async () => {
- const query = 'SELECT id, name FROM sample';
+ const query = 'SELECT id, name FROM student';
const result = await executeSELECTQuery(query);
expect(result.length).toBeGreaterThan(0);
expect(result[0]).toHaveProperty('id');
@@ -48,7 +48,7 @@ test('Execute SQL Query', async () => {
const executeSELECTQuery = require('../src/index');
test('Execute SQL Query with WHERE Clause', async () => {
- const query = 'SELECT id, name FROM sample WHERE age = 25';
+ 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');
@@ -57,11 +57,11 @@ test('Execute SQL Query with WHERE Clause', async () => {
});
test('Parse SQL Query with Multiple WHERE Clauses', () => {
- const query = 'SELECT id, name FROM sample WHERE age = 30 AND name = John';
+ const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John';
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample',
+ table: 'student',
whereClauses: [{
"field": "age",
"operator": "=",
@@ -75,7 +75,7 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
});
test('Execute SQL Query with Multiple WHERE Clause', async () => {
- const query = 'SELECT id, name FROM sample WHERE age = 30 AND name = John';
+ 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' });
@@ -83,15 +83,20 @@ test('Execute SQL Query with Multiple WHERE Clause', async () => {
// tests/index.test.js
test('Execute SQL Query with Greater Than', async () => {
- const queryWithGT = 'SELECT id FROM sample WHERE age > 22';
+ 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 Not Equal to', async () => {
- const queryWithGT = 'SELECT name FROM sample WHERE age != 25';
+ const queryWithGT = 'SELECT name FROM student 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('Parse SQL Query with INNER JOIN', async () => {/*implement*/});
+test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => {/*implement*/});
+test('Execute SQL Query with INNER JOIN', async () => {/*implement*/});
+test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => {/*implement*/});
\ No newline at end of file
diff --git a/tests/step-02/index.test.js b/tests/step-02/index.test.js
index a5467ee48..077af2138 100644
--- a/tests/step-02/index.test.js
+++ b/tests/step-02/index.test.js
@@ -1,7 +1,7 @@
const readCSV = require('../../src/csvReader');
test('Read CSV File', async () => {
- const data = await readCSV('./sample.csv');
+ const data = await readCSV('./student.csv');
expect(data.length).toBeGreaterThan(0);
expect(data.length).toBe(3);
expect(data[0].name).toBe('John');
diff --git a/tests/step-03/index.test.js b/tests/step-03/index.test.js
index d5822faf9..2e5998946 100644
--- a/tests/step-03/index.test.js
+++ b/tests/step-03/index.test.js
@@ -2,7 +2,7 @@ const readCSV = require('../../src/csvReader');
const parseQuery = require('../../src/queryParser');
test('Read CSV File', async () => {
- const data = await readCSV('./sample.csv');
+ const data = await readCSV('./student.csv');
expect(data.length).toBeGreaterThan(0);
expect(data.length).toBe(3);
expect(data[0].name).toBe('John');
@@ -10,11 +10,13 @@ test('Read CSV File', async () => {
});
test('Parse SQL Query', () => {
- const query = 'SELECT id, name FROM sample';
+ const query = 'SELECT id, name FROM student';
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample',
- whereClauses:[]
+ table: 'student',
+ whereClauses:[],
+ joinTable:null,
+ joinCondition:null
});
});
\ No newline at end of file
diff --git a/tests/step-04/index.test.js b/tests/step-04/index.test.js
index 6c104d895..211e1df57 100644
--- a/tests/step-04/index.test.js
+++ b/tests/step-04/index.test.js
@@ -3,7 +3,7 @@ const parseQuery = require('../../src/queryParser');
const executeSELECTQuery = require('../../src/index');
test('Read CSV File', async () => {
- const data = await readCSV('./sample.csv');
+ const data = await readCSV('./student.csv');
expect(data.length).toBeGreaterThan(0);
expect(data.length).toBe(3);
expect(data[0].name).toBe('John');
@@ -11,17 +11,19 @@ test('Read CSV File', async () => {
});
test('Parse SQL Query', () => {
- const query = 'SELECT id, name FROM sample';
+ const query = 'SELECT id, name FROM student';
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample',
- whereClauses: []
+ table: 'student',
+ whereClauses:[],
+ joinTable:null,
+ joinCondition:null
});
});
test('Execute SQL Query', async () => {
- const query = 'SELECT id, name FROM sample';
+ const query = 'SELECT id, name FROM student';
const result = await executeSELECTQuery(query);
expect(result.length).toBeGreaterThan(0);
expect(result[0]).toHaveProperty('id');
diff --git a/tests/step-05/index.test.js b/tests/step-05/index.test.js
index 37be0d154..c3bb75627 100644
--- a/tests/step-05/index.test.js
+++ b/tests/step-05/index.test.js
@@ -3,7 +3,7 @@ const parseQuery = require('../../src/queryParser');
const executeSELECTQuery = require('../../src/index');
test('Read CSV File', async () => {
- const data = await readCSV('./sample.csv');
+ const data = await readCSV('./student.csv');
expect(data.length).toBeGreaterThan(0);
expect(data.length).toBe(3);
expect(data[0].name).toBe('John');
@@ -11,17 +11,19 @@ test('Read CSV File', async () => {
});
test('Parse SQL Query', () => {
- const query = 'SELECT id, name FROM sample';
+ const query = 'SELECT id, name FROM student';
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample',
- whereClauses: []
+ table: 'student',
+ whereClauses: [],
+ joinTable:null,
+ joinCondition:null
});
});
test('Execute SQL Query', async () => {
- const query = 'SELECT id, name FROM sample';
+ const query = 'SELECT id, name FROM student';
const result = await executeSELECTQuery(query);
expect(result.length).toBeGreaterThan(0);
expect(result[0]).toHaveProperty('id');
@@ -31,22 +33,25 @@ test('Execute SQL Query', async () => {
});
test('Parse SQL Query with WHERE Clause', () => {
- const query = 'SELECT id, name FROM sample WHERE age = 25';
+ const query = 'SELECT id, name FROM student WHERE age = 25';
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample',
+ table: 'student',
whereClauses: [{
"field":"age",
"operator":"=",
"value":"25"
}
- ]
+ ],
+ joinTable:null,
+ joinCondition:null
});
+
});
test('Execute SQL Query with WHERE Clause', async () => {
- const query = 'SELECT id, name FROM sample WHERE age = 25';
+ 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');
diff --git a/tests/step-06/index.test.js b/tests/step-06/index.test.js
index 2e2ef6416..22fea6a8f 100644
--- a/tests/step-06/index.test.js
+++ b/tests/step-06/index.test.js
@@ -3,7 +3,7 @@ const parseQuery = require('../../src/queryParser');
const executeSELECTQuery = require('../../src/index');
test('Read CSV File', async () => {
- const data = await readCSV('./sample.csv');
+ const data = await readCSV('./student.csv');
expect(data.length).toBeGreaterThan(0);
expect(data.length).toBe(3);
expect(data[0].name).toBe('John');
@@ -16,12 +16,14 @@ test('Parse SQL Query', () => {
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'sample',
- whereClauses: []
+ whereClauses: [],
+ joinTable:null,
+ joinCondition:null
});
});
test('Execute SQL Query', async () => {
- const query = 'SELECT id, name FROM sample';
+ const query = 'SELECT id, name FROM student';
const result = await executeSELECTQuery(query);
expect(result.length).toBeGreaterThan(0);
expect(result[0]).toHaveProperty('id');
@@ -31,21 +33,23 @@ test('Execute SQL Query', async () => {
});
test('Parse SQL Query with WHERE Clause', () => {
- const query = 'SELECT id, name FROM sample WHERE age = 25';
+ const query = 'SELECT id, name FROM student WHERE age = 25';
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample',
+ table: 'student',
whereClauses: [{
field: "age",
operator: "=",
value: "25",
}],
+ joinTable:null,
+ joinCondition:null
});
});
test('Execute SQL Query with WHERE Clause', async () => {
- const query = 'SELECT id, name FROM sample WHERE age = 25';
+ 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');
@@ -54,11 +58,11 @@ test('Execute SQL Query with WHERE Clause', async () => {
});
test('Parse SQL Query with Multiple WHERE Clauses', () => {
- const query = 'SELECT id, name FROM sample WHERE age = 30 AND name = John';
+ const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John';
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample',
+ table: 'student',
whereClauses: [{
"field": "age",
"operator": "=",
@@ -67,12 +71,14 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
"field": "name",
"operator": "=",
"value": "John",
- }]
+ }],
+ joinTable:null,
+ joinCondition:null
});
});
test('Execute SQL Query with Multiple WHERE Clause', async () => {
- const query = 'SELECT id, name FROM sample WHERE age = 30 AND name = John';
+ 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' });
diff --git a/tests/step-07/index.test.js b/tests/step-07/index.test.js
index ee0ebed5e..ae2e74589 100644
--- a/tests/step-07/index.test.js
+++ b/tests/step-07/index.test.js
@@ -3,7 +3,7 @@ const parseQuery = require('../../src/queryParser');
const executeSELECTQuery = require('../../src/index');
test('Read CSV File', async () => {
- const data = await readCSV('./sample.csv');
+ const data = await readCSV('./student.csv');
expect(data.length).toBeGreaterThan(0);
expect(data.length).toBe(3);
expect(data[0].name).toBe('John');
@@ -16,12 +16,14 @@ test('Parse SQL Query', () => {
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'sample',
- whereClauses: []
+ whereClauses: [],
+ joinTable:null,
+ joinCondition:null
});
});
test('Execute SQL Query', async () => {
- const query = 'SELECT id, name FROM sample';
+ const query = 'SELECT id, name FROM student';
const result = await executeSELECTQuery(query);
expect(result.length).toBeGreaterThan(0);
expect(result[0]).toHaveProperty('id');
@@ -31,21 +33,23 @@ test('Execute SQL Query', async () => {
});
test('Parse SQL Query with WHERE Clause', () => {
- const query = 'SELECT id, name FROM sample WHERE age = 25';
+ const query = 'SELECT id, name FROM student WHERE age = 25';
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample',
+ table: 'student',
whereClauses: [{
field: "age",
operator: "=",
value: "25",
}],
+ joinCondition: null,
+ joinTable: null
});
});
test('Execute SQL Query with WHERE Clause', async () => {
- const query = 'SELECT id, name FROM sample WHERE age = 25';
+ 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');
@@ -54,11 +58,11 @@ test('Execute SQL Query with WHERE Clause', async () => {
});
test('Parse SQL Query with Multiple WHERE Clauses', () => {
- const query = 'SELECT id, name FROM sample WHERE age = 30 AND name = John';
+ const query = 'SELECT id, name FROM student WHERE age = 30 AND name = John';
const parsed = parseQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
- table: 'sample',
+ table: 'student',
whereClauses: [{
"field": "age",
"operator": "=",
@@ -67,26 +71,28 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
"field": "name",
"operator": "=",
"value": "John",
- }]
+ }],
+ joinCondition: null,
+ joinTable: null
});
});
test('Execute SQL Query with Multiple WHERE Clause', async () => {
- const query = 'SELECT id, name FROM sample WHERE age = 30 AND name = John';
+ 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 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 Not Equal to', async () => {
- const queryWithGT = 'SELECT name FROM sample WHERE age != 25';
+ const queryWithGT = 'SELECT name FROM student WHERE age != 25';
const result = await executeSELECTQuery(queryWithGT);
expect(result.length).toEqual(2);
expect(result[0]).toHaveProperty('name');
From da8eb53d97654582308ebf9aef08e2d26b79f7cd Mon Sep 17 00:00:00 2001
From: sparking_chips
Date: Sun, 14 Apr 2024 02:58:02 +0530
Subject: [PATCH 10/14] completed till task 10
---
enrollment.csv | 3 +-
src/index.js | 305 +++++++++++++++++++++++++++++++-----
src/queryParser.js | 171 ++++++++++++++++++--
student.csv | 3 +-
tests/step-02/index.test.js | 2 +-
tests/step-03/index.test.js | 9 +-
tests/step-04/index.test.js | 9 +-
tests/step-05/index.test.js | 15 +-
tests/step-06/index.test.js | 19 ++-
tests/step-07/index.test.js | 23 ++-
tests/step-08/index.test.js | 33 ++--
tests/step-09/index.test.js | 22 ++-
12 files changed, 520 insertions(+), 94 deletions(-)
diff --git a/enrollment.csv b/enrollment.csv
index 779ff5501..e80af8d93 100644
--- a/enrollment.csv
+++ b/enrollment.csv
@@ -2,4 +2,5 @@ student_id,course
1,Mathematics
1,Physics
2,Chemistry
-3,Mathematics
\ No newline at end of file
+3,Mathematics
+5,Biology
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 8cfaca985..f75090243 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,59 +1,286 @@
// src/index.js
-const parseQuery = require('./queryParser');
+const {parseQuery} = require('./queryParser');
const readCSV = require('./csvReader');
-// src/index.js
-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}`);
+// Helper functions for different JOIN types
+function performInnerJoin(data, joinData, joinCondition, fields, table) {
+ return data.flatMap(mainRow => {
+ const matchedJoinRows = joinData.filter(joinRow => {
+ const mainValue = mainRow[joinCondition.left.split('.')[1]];
+ const joinValue = joinRow[joinCondition.right.split('.')[1]];
+ return mainValue === joinValue;
+ });
+
+ // If there are matching rows, create a row for each match
+ return matchedJoinRows.map(joinRow => {
+ return fields.reduce((acc, field) => {
+ const [tableName, fieldName] = field.split('.');
+ acc[field] = tableName === table ? mainRow[fieldName] : joinRow[fieldName];
+ return acc;
+ }, {});
+ });
+ });
+}
+
+function performLeftJoin(data, joinData, joinCondition, fields, table) {
+ const leftJoinedData = data.flatMap(mainRow => {
+ const matchedJoinRows = joinData.filter(joinRow => {
+ const mainValue = mainRow[joinCondition.left.split('.')[1]];
+ const joinValue = joinRow[joinCondition.right.split('.')[1]];
+ return mainValue === joinValue;
+ });
+
+ if (matchedJoinRows.length === 0) {
+ return [createResultRow(mainRow, null, fields, table, true)];
+ }
+ return matchedJoinRows.map(joinRow => createResultRow(mainRow, joinRow, fields, table, true));
+
+ });
+ return leftJoinedData;
+}
+
+function createResultRow(mainRow, joinRow, fields, table, includeAllMainFields) {
+ const resultRow = {};
+ if (includeAllMainFields) {
+ // Include all fields from the main table
+ Object.keys(mainRow || {}).forEach(key => {
+ const prefixedKey = `${table}.${key}`;
+ resultRow[prefixedKey] = mainRow ? mainRow[key] : null;
+ });
}
+ // Now, add or overwrite with the fields specified in the query
+ fields.forEach(field => {
+ const [tableName, fieldName] = field.includes('.') ? field.split('.') : [table, field];
+ resultRow[field] = tableName === table && mainRow ? mainRow[fieldName] : joinRow ? joinRow[fieldName] : null;
+ });
+ return resultRow;
+}
+
+function performRightJoin(data, joinData, joinCondition, fields, table) {
+ // Cache the structure of a main table row (keys only)
+ console.log("Inside Right join")
+ console.log("data",data)
+ console.log("Joindata",joinData)
+ console.log("JoinCodnitio",joinCondition)
+ console.log("fields",fields)
+ const RowStructure = data.length > 0 ? Object.keys(data[0]).reduce((acc, key) => {
+ acc[key] = null; // Set all values to null initially
+ return acc;
+ }, {}) : {};
+ let rightJoinedData = joinData.map(joinRow => {
+ const mainRowMatch = data.find(mainRow => {
+ const mainValue = getValueFromGivenRow(mainRow, joinCondition.left);
+ const joinValue = getValueFromGivenRow(joinRow, joinCondition.right);
+ return mainValue === joinValue;
+ });
+ // Use the cached structure if no match is found
+ const mainRowToUse = mainRowMatch || RowStructure;
+ // Include all necessary fields from the 'student' table
+ return createResultRow(mainRowToUse, joinRow, fields, table, true);
+ });
+ console.log("rightJOinedDAta",rightJoinedData)
+ return rightJoinedData
+}
+
+function getValueFromGivenRow(row, compoundFieldName) {
+ const [tableName, fieldName] = compoundFieldName.split('.');
+ return row[`${tableName}.${fieldName}`] || row[fieldName];
+}
+
+function applyGroupBy(data, groupByFields, aggregateFunctions) {
+ const groupResult = {};
+ data.forEach(row => {
+ // Generate a key for the group
+ const Key = groupByFields.map(field => row[field]).join('-');
+ // Initialize group in results if it doesn't exist
+ if (!groupResult[Key]) {
+ groupResult[Key] = { count: 0, sums: {}, mins: {}, maxes: {} };
+ groupByFields.forEach(field => groupResult[Key][field] = row[field]);
+ }
+ // Aggregate calculations
+ groupResult[Key].count += 1;
+ aggregateFunctions.forEach(func => {
+ const match = /(\w+)\((\w+)\)/.exec(func);
+ if (match) {
+ const [, aggregateFunc, aggregateField] = match;
+ const value = parseFloat(row[aggregateField]);
+ switch (aggregateFunc.toUpperCase()) {
+ case 'SUM':
+ groupResult[Key].sums[aggregateField] = (groupResult[Key].sums[aggregateField] || 0) + value;
+ break;
+ case 'MIN':
+ groupResult[Key].mins[aggregateField] = Math.min(groupResult[Key].mins[aggregateField] || value, value);
+ break;
+ case 'MAX':
+ groupResult[Key].maxes[aggregateField] = Math.max(groupResult[Key].maxes[aggregateField] || value, value);
+ break;
+ // Additional aggregate functions can be added here
+ }
+ }
+ });
+ });
+ // Convert grouped results into an array format
+ return Object.values(groupResult).map(group => {
+ // Construct the final grouped object based on required fields
+ const finalGroup = {};
+ groupByFields.forEach(field => finalGroup[field] = group[field]);
+ aggregateFunctions.forEach(func => {
+ const match = /(\w+)\((\*|\w+)\)/.exec(func);
+ if (match) {
+ const [, aggregateFunc, aggregateField] = match;
+ switch (aggregateFunc.toUpperCase()) {
+ case 'SUM':
+ finalGroup[func] = group.sums[aggregateField];
+ break;
+ case 'MIN':
+ finalGroup[func] = group.mins[aggregateField];
+ break;
+ case 'MAX':
+ finalGroup[func] = group.maxes[aggregateField];
+ break;
+ case 'COUNT':
+ finalGroup[func] = group.count;
+ break;
+ // Additional aggregate functions can be handled here
+ }
+ }
+ });
+ return finalGroup;
+ });
}
async function executeSELECTQuery(query) {
- const { fields, table, whereClauses, joinTable, joinCondition } = parseQuery(query);
+ const { fields, table, whereClauses,joinType, joinTable, joinCondition,groupByFields,hasAggregateWithoutGroupBy } = parseQuery(query);
let data = await readCSV(`${table}.csv`);
-
- // Perform INNER JOIN if specified
+ console.log("data before join condition",data)
+ // LOGIC for applying the joins
if (joinTable && joinCondition) {
const joinData = await readCSV(`${joinTable}.csv`);
- 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;
- }, {});
- });
- });
- }
-
- // 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 => {
+ switch (joinType.toUpperCase()) {
+ case 'INNER':
+ data = performInnerJoin(data, joinData, joinCondition, fields, table);
+ break;
+ case 'LEFT':
+ data = performLeftJoin(data, joinData, joinCondition, fields, table);
+ break;
+ case 'RIGHT':
+ data = performRightJoin(data, joinData, joinCondition, fields, table);
+ break;
+ default:
+ throw new Error(`Unsupported join type`);
+ // Handle default case or unsupported JOIN types
+ }
+ }
+
+ console.log("data",data)
+ let filteredData = whereClauses.length > 0
+ ? data.filter(row => whereClauses.every(clause => evaluateCondition(row, clause)))
+ : data;
+ console.log("filtered Data after condition",filteredData)
+
+ let groupData = filteredData;
+ if(hasAggregateWithoutGroupBy){
+ // handling queries where there are no Group by and we are doing Aggregrate
+ const output = {};
+
+ fields.forEach(field => {
+ const match = /(\w+)\((\*|\w+)\)/.exec(field);
+ if (match) {
+ const [, aggregrateFunc, aggregrateField] = match;
+ switch (aggregrateFunc.toUpperCase()) {
+ case 'COUNT':
+ output[field] = filteredData.length;
+ break;
+ case 'SUM':
+ output[field] = filteredData.reduce((acc, row) => acc + parseFloat(row[aggregrateField]), 0);
+ break;
+ case 'AVG':
+ output[field] = filteredData.reduce((acc, row) => acc + parseFloat(row[aggregrateField]), 0) / filteredData.length;
+ break;
+ case 'MIN':
+ output[field] = Math.min(...filteredData.map(row => parseFloat(row[aggregrateField])));
+ break;
+ case 'MAX':
+ output[field] = Math.max(...filteredData.map(row => parseFloat(row[aggregrateField])));
+ break;
+ // Additional aggregate functions can be handled here
+ }
+ }
+ });
+
+ return [output];
+ }else if(groupByFields){
+ groupData = applyGroupBy(filteredData,groupByFields,fields)
+ return groupData;
+ }else{
+ return groupData.map(row => {
const selectedRow = {};
fields.forEach(field => {
selectedRow[field] = row[field];
});
return selectedRow;
});
+ }
+ // if (groupByFields) {
+ // data = applyGroupBy(data, groupByFields, fields);
+ // }
+
+ // 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) {
+ let { field, operator, value } = clause;
+
+ if (row[field] === undefined) {
+ throw new Error(`Invalid field`);
+ }
+ // Parse row value and condition value based on their actual types
+ const rowValue = parsingValue(row[field]);
+ let conditionValue = parsingValue(value);
+ console.log("rowValue",rowValue);
+ console.log("conditionValue",conditionValue);
+ // Compare the field value with the condition value
+ switch (operator) {
+ case '=': return rowValue === conditionValue;
+ case '!=': return rowValue !== conditionValue;
+ case '>': return rowValue > conditionValue;
+ case '<': return rowValue < conditionValue;
+ case '>=': return rowValue >= conditionValue;
+ case '<=': return rowValue <= conditionValue;
+ default: throw new Error(`Unsupported operator: ${operator}`);
+ }
+}
+
+function parsingValue(value) {
+ // Return null or undefined as is
+ if (value === null || value === undefined) {
+ return value;
+ }
+ // If the value is a string enclosed in single or double quotes, remove them
+ if (typeof value === 'string' && ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"')))) {
+ value = value.substring(1, value.length - 1);
+ }
+ // Check if value is a number
+ if (!isNaN(value) && value.trim() !== '') {
+ return Number(value);
+ }
+ // Assume value is a string if not a number
+ return value;
+}
+
+const query1=`SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`;
+const ret = executeSELECTQuery(query1)
+
module.exports = executeSELECTQuery;
\ No newline at end of file
diff --git a/src/queryParser.js b/src/queryParser.js
index 0222adae1..c78051279 100644
--- a/src/queryParser.js
+++ b/src/queryParser.js
@@ -4,7 +4,8 @@
function parseQuery(query) {
// First, let's trim the query to remove any leading/trailing whitespaces
query = query.trim();
-
+ const groupByRegex = /\sGROUP BY\s(.+)/i;
+ const groupByMatch = query.match(groupByRegex);
// Initialize variables for different parts of the query
let selectPart, fromPart;
@@ -13,10 +14,14 @@ function parseQuery(query) {
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;
+ let whereClause = whereSplit.length > 1 ? whereSplit[1].trim() : null;
+if (whereClause && whereClause.includes('GROUP BY')) {
+ whereClause = whereClause.split(/\sGROUP\sBY\s/i)[0].trim();
+}
+
// Split the remaining query at the JOIN clause if it exists
- const joinSplit = query.split(/\sINNER JOIN\s/i);
+ const joinSplit = query.split(/\s(INNER|LEFT|RIGHT) JOIN\s/i);
selectPart = joinSplit[0].trim(); // Everything before JOIN clause
// JOIN clause is the second part after splitting, if it exists
@@ -29,24 +34,129 @@ function parseQuery(query) {
throw new Error('Invalid SELECT format');
}
- const [, fields, table] = selectMatch;
+ const [, fields, rawTable] = selectMatch;
+
+ let joinType ;
+ let joinTable ;
+ let joinCondition ;
// Parse the JOIN part if it exists
- let joinTable = null, joinCondition = null;
if (joinPart) {
- const joinRegex = /^(.+?)\sON\s([\w.]+)\s*=\s*([\w.]+)/i;
- const joinMatch = joinPart.match(joinRegex);
- if (!joinMatch) {
- throw new Error('Invalid JOIN format');
+ ( { joinType, joinTable, joinCondition } = parseJoinClause(query));
+ }else{
+ joinType=null;
+ joinTable=null;
+ joinCondition=null;
+ }
+
+ // Parse the WHERE part if it exists
+ let whereClauses = [];
+ if (whereClause) {
+ whereClauses = parseWhereClause(whereClause);
+ }
+
+ // Updated regex to capture GROUP BY clause
+
+ const table = groupByMatch ? rawTable.split('GROUP BY')[0].trim() : rawTable.trim(); // Extract table name without GROUP BY
+
+
+ const aggregateFunctionRegex = /\b(COUNT|SUM|AVG|MIN|MAX)\(.+?\)/i;
+ const hasAggregateFunction = fields.match(aggregateFunctionRegex);
+
+ let hasAggregateWithoutGroupBy = false;
+ let groupByFields = null;
+
+ if (groupByMatch) {
+ groupByFields = groupByMatch[1].split(',').map(field => field.trim());
+ }
+ if (hasAggregateFunction && !groupByMatch) {
+ hasAggregateWithoutGroupBy = true;
+ }
+
+ return {
+ fields: fields.split(',').map(field => field.trim()),
+ table: table.trim(),
+ whereClauses,
+ joinType,
+ joinTable,
+ joinCondition,
+ groupByFields,
+ hasAggregateWithoutGroupBy
+ };
+}
+
+// src/queryParser.js
+function parseWhereClause(whereString) {
+ const conditionRegex = /(.*?)(=|!=|>|<|>=|<=)(.*)/;
+ return whereString.split(/ AND | OR /i).map(conditionString => {
+ const match = conditionString.match(conditionRegex);
+ if (match) {
+ const [, field, operator, value] = match;
+ return { field: field.trim(), operator, value: value.trim() };
}
+ throw new Error('Invalid WHERE clause format');
+ });
+}
+
+function parseJoinClause(query) {
+ const joinRegex = /\s(INNER|LEFT|RIGHT) JOIN\s(.+?)\sON\s([\w.]+)\s*=\s*([\w.]+)/i;
+ const joinMatch = query.match(joinRegex);
- joinTable = joinMatch[1].trim();
- joinCondition = {
- left: joinMatch[2].trim(),
- right: joinMatch[3].trim()
+ if (joinMatch) {
+ return {
+ joinType: joinMatch[1].trim(),
+ joinTable: joinMatch[2].trim(),
+ joinCondition: {
+ left: joinMatch[3].trim(),
+ right: joinMatch[4].trim()
+ }
};
}
+ // src/queryParser.js
+
+
+function parseQuery(query) {
+ // First, let's trim the query to remove any leading/trailing whitespaces
+ query = query.trim();
+
+ // 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
+
+ // JOIN clause is the second part after splitting, if it exists
+ const joinPart = joinSplit.length > 1 ? joinSplit[1].trim() : null;
+
+ // 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;
+ let joinType ;
+ let joinTable ;
+ let joinCondition ;
+ // Parse the JOIN part if it exists
+ if (joinPart) {
+ ( { joinType, joinTable, joinCondition } = parseJoinClause(query));
+ }else{
+ joinType=null;
+ joinTable=null;
+ joinCondition=null;
+ }
+
// Parse the WHERE part if it exists
let whereClauses = [];
if (whereClause) {
@@ -57,11 +167,13 @@ function parseQuery(query) {
fields: fields.split(',').map(field => field.trim()),
table: table.trim(),
whereClauses,
+ joinType,
joinTable,
joinCondition
};
}
+
// src/queryParser.js
function parseWhereClause(whereString) {
const conditionRegex = /(.*?)(=|!=|>|<|>=|<=)(.*)/;
@@ -74,4 +186,35 @@ function parseWhereClause(whereString) {
throw new Error('Invalid WHERE clause format');
});
}
-module.exports = parseQuery;
\ No newline at end of file
+
+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
+ };
+}
+
+module.exports = {parseQuery,parseJoinClause};
+ return {
+ joinType: null,
+ joinTable: null,
+ joinCondition: null
+ };
+}
+
+module.exports = {parseQuery,parseJoinClause};
\ No newline at end of file
diff --git a/student.csv b/student.csv
index 9e7a9fa25..e9c960121 100644
--- a/student.csv
+++ b/student.csv
@@ -1,4 +1,5 @@
id,name,age
1,John,30
2,Jane,25
-3,Bob,22
\ No newline at end of file
+3,Bob,22
+4,Alice,24
\ No newline at end of file
diff --git a/tests/step-02/index.test.js b/tests/step-02/index.test.js
index 077af2138..d9300b8f4 100644
--- a/tests/step-02/index.test.js
+++ b/tests/step-02/index.test.js
@@ -3,7 +3,7 @@ const readCSV = require('../../src/csvReader');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
expect(data.length).toBeGreaterThan(0);
- expect(data.length).toBe(3);
+ 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
});
\ No newline at end of file
diff --git a/tests/step-03/index.test.js b/tests/step-03/index.test.js
index 2e5998946..1e5c5ad16 100644
--- a/tests/step-03/index.test.js
+++ b/tests/step-03/index.test.js
@@ -1,10 +1,10 @@
const readCSV = require('../../src/csvReader');
-const parseQuery = require('../../src/queryParser');
+const {parseQuery} = require('../../src/queryParser');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
expect(data.length).toBeGreaterThan(0);
- expect(data.length).toBe(3);
+ 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
});
@@ -17,6 +17,9 @@ test('Parse SQL Query', () => {
table: 'student',
whereClauses:[],
joinTable:null,
- joinCondition:null
+ joinCondition:null,
+ joinType:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
\ No newline at end of file
diff --git a/tests/step-04/index.test.js b/tests/step-04/index.test.js
index 211e1df57..716112396 100644
--- a/tests/step-04/index.test.js
+++ b/tests/step-04/index.test.js
@@ -1,11 +1,11 @@
const readCSV = require('../../src/csvReader');
-const parseQuery = require('../../src/queryParser');
+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(3);
+ 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
});
@@ -18,7 +18,10 @@ test('Parse SQL Query', () => {
table: 'student',
whereClauses:[],
joinTable:null,
- joinCondition:null
+ joinCondition:null,
+ joinType:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
diff --git a/tests/step-05/index.test.js b/tests/step-05/index.test.js
index c3bb75627..3e953a563 100644
--- a/tests/step-05/index.test.js
+++ b/tests/step-05/index.test.js
@@ -1,11 +1,11 @@
const readCSV = require('../../src/csvReader');
-const parseQuery = require('../../src/queryParser');
+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(3);
+ 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
});
@@ -18,7 +18,10 @@ test('Parse SQL Query', () => {
table: 'student',
whereClauses: [],
joinTable:null,
- joinCondition:null
+ joinCondition:null,
+ joinType:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
@@ -45,9 +48,11 @@ test('Parse SQL Query with WHERE Clause', () => {
}
],
joinTable:null,
- joinCondition:null
+ joinCondition:null,
+ joinType:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
-
});
test('Execute SQL Query with WHERE Clause', async () => {
diff --git a/tests/step-06/index.test.js b/tests/step-06/index.test.js
index 22fea6a8f..37e7101dc 100644
--- a/tests/step-06/index.test.js
+++ b/tests/step-06/index.test.js
@@ -1,11 +1,11 @@
const readCSV = require('../../src/csvReader');
-const parseQuery = require('../../src/queryParser');
+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(3);
+ 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
});
@@ -18,7 +18,10 @@ test('Parse SQL Query', () => {
table: 'sample',
whereClauses: [],
joinTable:null,
- joinCondition:null
+ joinCondition:null,
+ joinType:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
@@ -44,7 +47,10 @@ test('Parse SQL Query with WHERE Clause', () => {
value: "25",
}],
joinTable:null,
- joinCondition:null
+ joinType:null,
+ joinCondition:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
@@ -73,7 +79,10 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
"value": "John",
}],
joinTable:null,
- joinCondition:null
+ joinCondition:null,
+ joinType:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
diff --git a/tests/step-07/index.test.js b/tests/step-07/index.test.js
index ae2e74589..daf4afbd8 100644
--- a/tests/step-07/index.test.js
+++ b/tests/step-07/index.test.js
@@ -1,11 +1,11 @@
const readCSV = require('../../src/csvReader');
-const parseQuery = require('../../src/queryParser');
+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(3);
+ 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
});
@@ -17,8 +17,11 @@ test('Parse SQL Query', () => {
fields: ['id', 'name'],
table: 'sample',
whereClauses: [],
+ joinType:null,
joinTable:null,
- joinCondition:null
+ joinCondition:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
@@ -44,7 +47,10 @@ test('Parse SQL Query with WHERE Clause', () => {
value: "25",
}],
joinCondition: null,
- joinTable: null
+ joinTable: null,
+ joinType:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
@@ -73,7 +79,10 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
"value": "John",
}],
joinCondition: null,
- joinTable: null
+ joinTable: null,
+ joinType:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
@@ -87,13 +96,13 @@ test('Execute SQL Query with Multiple WHERE Clause', async () => {
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.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.length).toEqual(3);
expect(result[0]).toHaveProperty('name');
});
\ No newline at end of file
diff --git a/tests/step-08/index.test.js b/tests/step-08/index.test.js
index aab1467e6..2a3d218bf 100644
--- a/tests/step-08/index.test.js
+++ b/tests/step-08/index.test.js
@@ -1,11 +1,11 @@
const readCSV = require('../../src/csvReader');
-const parseQuery = require('../../src/queryParser');
+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(3);
+ 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
});
@@ -17,8 +17,11 @@ test('Parse SQL Query', () => {
fields: ['id', 'name'],
table: 'student',
whereClauses: [],
+ joinType:null,
+ joinTable: null,
joinCondition: null,
- joinTable: null
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
@@ -44,7 +47,10 @@ test('Parse SQL Query with WHERE Clause', () => {
"value": "25",
}],
joinCondition: null,
- joinTable: null
+ joinTable: null,
+ joinType:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
@@ -73,7 +79,10 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
"value": "John",
}],
joinCondition: null,
- joinTable: null
+ joinTable: null,
+ joinType:null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
@@ -87,14 +96,14 @@ test('Execute SQL Query with Complex WHERE Clause', async () => {
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.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.length).toEqual(3);
expect(result[0]).toHaveProperty('name');
});
@@ -106,7 +115,10 @@ test('Parse SQL Query with INNER JOIN', async () => {
table: 'student',
whereClauses: [],
joinTable: 'enrollment',
- joinCondition: { left: 'student.id', right: 'enrollment.student_id' }
+ joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
+ joinType: 'INNER',
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
})
});
@@ -118,7 +130,10 @@ test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => {
table: 'student',
whereClauses: [{ field: 'student.age', operator: '>', value: '20' }],
joinTable: 'enrollment',
- joinCondition: { left: 'student.id', right: 'enrollment.student_id' }
+ joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
+ joinType: 'INNER',
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
})
});
diff --git a/tests/step-09/index.test.js b/tests/step-09/index.test.js
index aaf711f5a..1efa5db47 100644
--- a/tests/step-09/index.test.js
+++ b/tests/step-09/index.test.js
@@ -17,9 +17,11 @@ test('Parse SQL Query', () => {
fields: ['id', 'name'],
table: 'student',
whereClauses: [],
- joinCondition: null,
+ joinType: null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false,
joinTable: null,
- joinType: null
+ joinCondition: null
});
});
@@ -46,7 +48,9 @@ test('Parse SQL Query with WHERE Clause', () => {
}],
joinCondition: null,
joinTable: null,
- joinType: null
+ joinType: null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
@@ -76,7 +80,9 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
}],
joinCondition: null,
joinTable: null,
- joinType: null
+ joinType: null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
});
});
@@ -110,7 +116,9 @@ test('Parse SQL Query with INNER JOIN', async () => {
whereClauses: [],
joinTable: 'enrollment',
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
- joinType: 'INNER'
+ joinType: 'INNER',
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
})
});
@@ -123,7 +131,9 @@ test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => {
whereClauses: [{ field: 'student.age', operator: '>', value: '20' }],
joinTable: 'enrollment',
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
- joinType: 'INNER'
+ joinType: 'INNER',
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false
})
});
From be102b4329c24bbc6c456160b30598a9042b26c6 Mon Sep 17 00:00:00 2001
From: sparking_chips
Date: Sun, 14 Apr 2024 12:20:49 +0530
Subject: [PATCH 11/14] completed till task 14
---
src/index.js | 85 +++++++++++++++------
src/queryParser.js | 142 ++++++++++++------------------------
tests/step-03/index.test.js | 6 +-
tests/step-04/index.test.js | 6 +-
tests/step-05/index.test.js | 11 ++-
tests/step-06/index.test.js | 16 +++-
tests/step-07/index.test.js | 16 +++-
tests/step-08/index.test.js | 54 +++++++++++---
tests/step-10/index.test.js | 100 ++++++++++++++++++++-----
tests/step-11/index.test.js | 81 +++++++++++++++-----
tests/step-12/index.test.js | 59 ++++++++++-----
tests/step-13/index.test.js | 61 +++++++++++-----
12 files changed, 421 insertions(+), 216 deletions(-)
diff --git a/src/index.js b/src/index.js
index f75090243..5df6d7876 100644
--- a/src/index.js
+++ b/src/index.js
@@ -151,10 +151,15 @@ function applyGroupBy(data, groupByFields, aggregateFunctions) {
}
async function executeSELECTQuery(query) {
- const { fields, table, whereClauses,joinType, joinTable, joinCondition,groupByFields,hasAggregateWithoutGroupBy } = parseQuery(query);
+ try{
+ const { fields, table, whereClauses,joinType, joinTable, joinCondition,groupByFields,hasAggregateWithoutGroupBy,orderByFields,limit,isDistinct } = parseQuery(query);
+
+ console.log("join Table",joinTable)
+ console.log("table",table)
let data = await readCSV(`${table}.csv`);
console.log("data before join condition",data)
// LOGIC for applying the joins
+ console.log("groupByfieds",groupByFields)
if (joinTable && joinCondition) {
const joinData = await readCSV(`${joinTable}.csv`);
switch (joinType.toUpperCase()) {
@@ -212,32 +217,63 @@ async function executeSELECTQuery(query) {
return [output];
}else if(groupByFields){
groupData = applyGroupBy(filteredData,groupByFields,fields)
+ console.log("Group dataa",groupData)
+
+ let orderOutput = groupData;
+ if(orderByFields){
+ orderOutput=groupData.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;
+ });
+ }
+
+ if (limit !== null) {
+ orderOutput = orderOutput.slice(0, limit);
+ }
+
+ if (isDistinct) {
+ groupData = [...new Map(groupData.map(item => [fields.map(field => item[field]).join('|'), item])).values()];
+ }
return groupData;
- }else{
- return groupData.map(row => {
+
+
+ } else{
+
+ // Order them by the specified fields
+ let orderOutput = groupData;
+ if (orderByFields) {
+ orderOutput = groupData.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;
+ });
+ }
+ if (limit !== null) {
+ orderOutput = orderOutput.slice(0, limit);
+ }
+ console.log("orderOUTput",orderOutput)
+ if (isDistinct) {
+ orderOutput = [...new Map(orderOutput.map(item => [fields.map(field => item[field]).join('|'), item])).values()];
+ }
+ return orderOutput.map(row => {
const selectedRow = {};
fields.forEach(field => {
- selectedRow[field] = row[field];
+ selectedRow[field]=row[field];
});
+ console.log("final Solution",selectedRow)
+
return selectedRow;
});
}
- // if (groupByFields) {
- // data = applyGroupBy(data, groupByFields, fields);
- // }
-
- // 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;
- // });
+}
+catch(error){
+ throw new Error(`Error executing query: ${error.message}`);
+}
}
function evaluateCondition(row, clause) {
@@ -280,7 +316,12 @@ function parsingValue(value) {
return value;
}
-const query1=`SELECT student.name, enrollment.course FROM student RIGHT JOIN enrollment ON student.id=enrollment.student_id WHERE enrollment.course = 'Chemistry'`;
-const ret = executeSELECTQuery(query1)
+async function func() {
+ 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
+ console.log("Result",result)
+}
+func()
module.exports = executeSELECTQuery;
\ No newline at end of file
diff --git a/src/queryParser.js b/src/queryParser.js
index c78051279..72239e7ff 100644
--- a/src/queryParser.js
+++ b/src/queryParser.js
@@ -3,8 +3,41 @@
function parseQuery(query) {
// First, let's trim the query to remove any leading/trailing whitespaces
+ try{
query = query.trim();
+
+ const limitRegex = /\sLIMIT\s(\d+)/i;
+ const orderByRegex = /\sORDER BY\s(.+)/i;
const groupByRegex = /\sGROUP BY\s(.+)/i;
+ const selectRegex = /^SELECT\s(.+?)\sFROM\s(.+)/i;
+ let isDistinct=false;
+ if (query.toUpperCase().includes('SELECT DISTINCT')) {
+ isDistinct = true;
+ query = query.replace('SELECT DISTINCT', 'SELECT');
+ }
+
+ const limitMatch = query.match(limitRegex);
+
+ let limit = null;
+ if (limitMatch) {
+ limit = parseInt(limitMatch[1]);
+ query = query.replace(limitRegex,'')
+ }
+ console.log("limit",limit)
+ console.log(typeof(limit))
+
+ const orderByMatch = query.match(orderByRegex);
+
+ let orderByFields = null;
+ if (orderByMatch) {
+ orderByFields = orderByMatch[1].split(',').map(field => {
+ const [fieldName, order] = field.trim().split(/\s+/);
+ return { fieldName, order: order ? order.toUpperCase() : 'ASC' };
+ });
+ query = query.replace(orderByRegex, '');
+ }
+
+
const groupByMatch = query.match(groupByRegex);
// Initialize variables for different parts of the query
let selectPart, fromPart;
@@ -28,15 +61,12 @@ if (whereClause && whereClause.includes('GROUP BY')) {
const joinPart = joinSplit.length > 1 ? joinSplit[1].trim() : null;
// 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, rawTable] = selectMatch;
-
let joinType ;
let joinTable ;
let joinCondition ;
@@ -81,99 +111,20 @@ if (whereClause && whereClause.includes('GROUP BY')) {
joinTable,
joinCondition,
groupByFields,
- hasAggregateWithoutGroupBy
+ hasAggregateWithoutGroupBy,
+ orderByFields,
+ limit,
+ isDistinct
};
+
}
-
-// src/queryParser.js
-function parseWhereClause(whereString) {
- const conditionRegex = /(.*?)(=|!=|>|<|>=|<=)(.*)/;
- return whereString.split(/ AND | OR /i).map(conditionString => {
- const match = conditionString.match(conditionRegex);
- if (match) {
- const [, field, operator, value] = match;
- return { field: field.trim(), operator, value: value.trim() };
- }
- throw new Error('Invalid WHERE clause format');
- });
+catch(error){
+ console.log(error)
+ throw new Error(`Query parsing error: ${error.message}`)
}
-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()
- }
- };
- }
-
- // src/queryParser.js
-
-
-function parseQuery(query) {
- // First, let's trim the query to remove any leading/trailing whitespaces
- query = query.trim();
-
- // 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
-
- // JOIN clause is the second part after splitting, if it exists
- const joinPart = joinSplit.length > 1 ? joinSplit[1].trim() : null;
-
- // 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;
- let joinType ;
- let joinTable ;
- let joinCondition ;
- // Parse the JOIN part if it exists
- if (joinPart) {
- ( { joinType, joinTable, joinCondition } = parseJoinClause(query));
- }else{
- joinType=null;
- joinTable=null;
- joinCondition=null;
- }
-
- // 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
- };
}
-
// src/queryParser.js
function parseWhereClause(whereString) {
const conditionRegex = /(.*?)(=|!=|>|<|>=|<=)(.*)/;
@@ -185,6 +136,7 @@ function parseWhereClause(whereString) {
}
throw new Error('Invalid WHERE clause format');
});
+
}
function parseJoinClause(query) {
@@ -209,12 +161,8 @@ function parseJoinClause(query) {
};
}
-module.exports = {parseQuery,parseJoinClause};
- return {
- joinType: null,
- joinTable: null,
- joinCondition: null
- };
-}
+const query = 'SELECT id, name FROM student ORDER BY age DESC LIMIT 2';
+const res = parseQuery(query)
+
module.exports = {parseQuery,parseJoinClause};
\ No newline at end of file
diff --git a/tests/step-03/index.test.js b/tests/step-03/index.test.js
index 1e5c5ad16..12727913f 100644
--- a/tests/step-03/index.test.js
+++ b/tests/step-03/index.test.js
@@ -20,6 +20,10 @@ test('Parse SQL Query', () => {
joinCondition:null,
joinType:null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
+
});
\ No newline at end of file
diff --git a/tests/step-04/index.test.js b/tests/step-04/index.test.js
index 716112396..06b1852fc 100644
--- a/tests/step-04/index.test.js
+++ b/tests/step-04/index.test.js
@@ -21,8 +21,12 @@ test('Parse SQL Query', () => {
joinCondition:null,
joinType:null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
+
});
test('Execute SQL Query', async () => {
diff --git a/tests/step-05/index.test.js b/tests/step-05/index.test.js
index 3e953a563..d7101520b 100644
--- a/tests/step-05/index.test.js
+++ b/tests/step-05/index.test.js
@@ -21,7 +21,10 @@ test('Parse SQL Query', () => {
joinCondition:null,
joinType:null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -51,8 +54,12 @@ test('Parse SQL Query with WHERE Clause', () => {
joinCondition:null,
joinType:null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
+
});
test('Execute SQL Query with WHERE Clause', async () => {
diff --git a/tests/step-06/index.test.js b/tests/step-06/index.test.js
index 37e7101dc..cc6ec58ec 100644
--- a/tests/step-06/index.test.js
+++ b/tests/step-06/index.test.js
@@ -21,7 +21,10 @@ test('Parse SQL Query', () => {
joinCondition:null,
joinType:null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -50,7 +53,10 @@ test('Parse SQL Query with WHERE Clause', () => {
joinType:null,
joinCondition:null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -82,8 +88,12 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
joinCondition:null,
joinType:null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
+
});
test('Execute SQL Query with Multiple WHERE Clause', async () => {
diff --git a/tests/step-07/index.test.js b/tests/step-07/index.test.js
index daf4afbd8..6af237b03 100644
--- a/tests/step-07/index.test.js
+++ b/tests/step-07/index.test.js
@@ -21,7 +21,10 @@ test('Parse SQL Query', () => {
joinTable:null,
joinCondition:null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -50,7 +53,10 @@ test('Parse SQL Query with WHERE Clause', () => {
joinTable: null,
joinType:null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -82,7 +88,10 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
joinTable: null,
joinType:null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -98,6 +107,7 @@ test('Execute SQL Query with Greater Than', async () => {
const result = await executeSELECTQuery(queryWithGT);
expect(result.length).toEqual(3);
expect(result[0]).toHaveProperty('id');
+
});
test('Execute SQL Query with Not Equal to', async () => {
diff --git a/tests/step-08/index.test.js b/tests/step-08/index.test.js
index 2a3d218bf..a020891de 100644
--- a/tests/step-08/index.test.js
+++ b/tests/step-08/index.test.js
@@ -17,11 +17,14 @@ test('Parse SQL Query', () => {
fields: ['id', 'name'],
table: 'student',
whereClauses: [],
- joinType:null,
+ joinType: null,
+ groupByFields: null,
+ hasAggregateWithoutGroupBy: false,
joinTable: null,
joinCondition: null,
- groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -48,9 +51,12 @@ test('Parse SQL Query with WHERE Clause', () => {
}],
joinCondition: null,
joinTable: null,
- joinType:null,
+ joinType: null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -80,9 +86,12 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
}],
joinCondition: null,
joinTable: null,
- joinType:null,
+ joinType: null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -118,7 +127,10 @@ test('Parse SQL Query with INNER JOIN', async () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
joinType: 'INNER',
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
})
});
@@ -133,7 +145,10 @@ test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
joinType: 'INNER',
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
})
});
@@ -179,4 +194,25 @@ test('Execute SQL Query with INNER JOIN and a WHERE Clause', async () => {
"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
diff --git a/tests/step-10/index.test.js b/tests/step-10/index.test.js
index 5e118eda5..bcc490d33 100644
--- a/tests/step-10/index.test.js
+++ b/tests/step-10/index.test.js
@@ -268,6 +268,9 @@ test('Parse SQL Query', () => {
joinType: null,
groupByFields: null,
hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -287,6 +290,9 @@ test('Parse SQL Query with WHERE Clause', () => {
joinType: null,
groupByFields: null,
hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -310,6 +316,9 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
joinType: null,
groupByFields: null,
hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -325,6 +334,9 @@ test('Parse SQL Query with INNER JOIN', async () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
groupByFields: null,
hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
})
});
@@ -340,6 +352,9 @@ test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
groupByFields: null,
hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
})
});
@@ -397,6 +412,9 @@ test('Parse LEFT Join Query Completely', () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
groupByFields: null,
hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
})
})
@@ -412,6 +430,9 @@ test('Parse LEFT Join Query Completely', () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
groupByFields: null,
hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
})
})
@@ -427,6 +448,9 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main tabl
"whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }],
groupByFields: null,
hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -442,6 +466,9 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join tabl
"whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }],
groupByFields: null,
hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -457,6 +484,9 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main tab
"whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }],
groupByFields: null,
hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -472,6 +502,9 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join tab
"whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }],
groupByFields: null,
hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -485,9 +518,12 @@ test('Parse COUNT Aggregate Query', () => {
whereClauses: [],
groupByFields: null,
hasAggregateWithoutGroupBy: true,
- "joinCondition": null,
- "joinTable": null,
- "joinType": null,
+ joinCondition: null,
+ joinTable: null,
+ joinType: null,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -501,9 +537,12 @@ test('Parse SUM Aggregate Query', () => {
whereClauses: [],
groupByFields: null,
hasAggregateWithoutGroupBy: true,
- "joinCondition": null,
- "joinTable": null,
- "joinType": null,
+ joinCondition: null,
+ joinTable: null,
+ joinType: null,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -516,9 +555,12 @@ test('Parse AVG Aggregate Query', () => {
whereClauses: [],
groupByFields: null,
hasAggregateWithoutGroupBy: true,
- "joinCondition": null,
- "joinTable": null,
- "joinType": null,
+ joinCondition: null,
+ joinTable: null,
+ joinType: null,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -531,9 +573,12 @@ test('Parse MIN Aggregate Query', () => {
whereClauses: [],
groupByFields: null,
hasAggregateWithoutGroupBy: true,
- "joinCondition": null,
- "joinTable": null,
- "joinType": null,
+ joinCondition: null,
+ joinTable: null,
+ joinType: null,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -546,9 +591,12 @@ test('Parse MAX Aggregate Query', () => {
whereClauses: [],
groupByFields: null,
hasAggregateWithoutGroupBy: true,
- "joinCondition": null,
- "joinTable": null,
- "joinType": null,
+ joinCondition: null,
+ joinTable: null,
+ joinType: null,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -563,7 +611,10 @@ test('Parse basic GROUP BY query', () => {
joinType: null,
joinTable: null,
joinCondition: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -578,7 +629,10 @@ test('Parse GROUP BY query with WHERE clause', () => {
joinType: null,
joinTable: null,
joinCondition: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -593,8 +647,12 @@ test('Parse GROUP BY query with multiple fields', () => {
joinType: null,
joinTable: null,
joinCondition: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ "limit": null,
+ isDistinct: false
});
+
});
test('Parse GROUP BY query with JOIN and WHERE clauses', () => {
@@ -611,6 +669,10 @@ test('Parse GROUP BY query with JOIN and WHERE clauses', () => {
left: 'student.id',
right: 'enrollment.student_id'
},
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ "limit": null,
+ isDistinct: 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..6462b3d6e 100644
--- a/tests/step-11/index.test.js
+++ b/tests/step-11/index.test.js
@@ -268,7 +268,9 @@ test('Parse SQL Query', () => {
joinType: null,
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -288,7 +290,9 @@ test('Parse SQL Query with WHERE Clause', () => {
joinType: null,
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -312,7 +316,9 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
joinType: null,
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -328,7 +334,9 @@ test('Parse SQL Query with INNER JOIN', async () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
})
});
@@ -344,7 +352,9 @@ test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
})
});
@@ -402,7 +412,9 @@ test('Parse LEFT Join Query Completely', () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
})
})
@@ -418,7 +430,9 @@ test('Parse LEFT Join Query Completely', () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
})
})
@@ -434,7 +448,9 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main tabl
"whereClauses": [{ "field": "student.age", "operator": ">", "value": "22" }],
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -450,7 +466,9 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join tabl
"whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Physics'" }],
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -466,7 +484,9 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main tab
"whereClauses": [{ "field": "student.age", "operator": "<", "value": "25" }],
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -482,7 +502,9 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join tab
"whereClauses": [{ "field": "enrollment.course", "operator": "=", "value": "'Chemistry'" }],
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -499,7 +521,9 @@ test('Parse COUNT Aggregate Query', () => {
"joinCondition": null,
"joinTable": null,
"joinType": null,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -516,7 +540,9 @@ test('Parse SUM Aggregate Query', () => {
"joinCondition": null,
"joinTable": null,
"joinType": null,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -532,7 +558,9 @@ test('Parse AVG Aggregate Query', () => {
"joinCondition": null,
"joinTable": null,
"joinType": null,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -548,7 +576,9 @@ test('Parse MIN Aggregate Query', () => {
"joinCondition": null,
"joinTable": null,
"joinType": null,
- "orderByFields": null
+ "orderByFields": null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -564,13 +594,16 @@ test('Parse MAX Aggregate Query', () => {
"joinCondition": null,
"joinTable": null,
"joinType": null,
- "orderByFields": 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',
@@ -580,7 +613,9 @@ test('Parse basic GROUP BY query', () => {
joinTable: null,
joinCondition: null,
hasAggregateWithoutGroupBy: false,
- orderByFields: null
+ orderByFields: null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -596,7 +631,9 @@ test('Parse GROUP BY query with WHERE clause', () => {
joinTable: null,
joinCondition: null,
hasAggregateWithoutGroupBy: false,
- orderByFields: null
+ orderByFields: null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -612,7 +649,9 @@ test('Parse GROUP BY query with multiple fields', () => {
joinTable: null,
joinCondition: null,
hasAggregateWithoutGroupBy: false,
- orderByFields: null
+ orderByFields: null,
+ "limit": null,
+ isDistinct: false
});
});
@@ -631,7 +670,9 @@ test('Parse GROUP BY query with JOIN and WHERE clauses', () => {
right: 'enrollment.student_id'
},
hasAggregateWithoutGroupBy: false,
- orderByFields: null
+ orderByFields: null,
+ "limit": null,
+ isDistinct: false
});
});
diff --git a/tests/step-12/index.test.js b/tests/step-12/index.test.js
index d15c77ef5..29b05003d 100644
--- a/tests/step-12/index.test.js
+++ b/tests/step-12/index.test.js
@@ -269,7 +269,8 @@ test('Parse SQL Query', () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -290,7 +291,8 @@ test('Parse SQL Query with WHERE Clause', () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -315,7 +317,8 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -332,7 +335,8 @@ test('Parse SQL Query with INNER JOIN', async () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
})
});
@@ -349,7 +353,8 @@ test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
})
});
@@ -408,7 +413,8 @@ test('Parse LEFT Join Query Completely', () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
})
})
@@ -425,7 +431,8 @@ test('Parse LEFT Join Query Completely', () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
})
})
@@ -442,7 +449,8 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main tabl
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -459,7 +467,8 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join tabl
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -476,7 +485,8 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main tab
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -493,7 +503,8 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join tab
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -511,7 +522,8 @@ test('Parse COUNT Aggregate Query', () => {
"joinTable": null,
"joinType": null,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -529,7 +541,8 @@ test('Parse SUM Aggregate Query', () => {
"joinTable": null,
"joinType": null,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -546,7 +559,8 @@ test('Parse AVG Aggregate Query', () => {
"joinTable": null,
"joinType": null,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -563,7 +577,8 @@ test('Parse MIN Aggregate Query', () => {
"joinTable": null,
"joinType": null,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -580,7 +595,8 @@ test('Parse MAX Aggregate Query', () => {
"joinTable": null,
"joinType": null,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -597,7 +613,8 @@ test('Parse basic GROUP BY query', () => {
joinCondition: null,
hasAggregateWithoutGroupBy: false,
orderByFields: null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -614,7 +631,8 @@ test('Parse GROUP BY query with WHERE clause', () => {
joinCondition: null,
hasAggregateWithoutGroupBy: false,
orderByFields: null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -631,7 +649,8 @@ test('Parse GROUP BY query with multiple fields', () => {
joinCondition: null,
hasAggregateWithoutGroupBy: false,
orderByFields: null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -652,6 +671,7 @@ test('Parse GROUP BY query with JOIN and WHERE clauses', () => {
hasAggregateWithoutGroupBy: false,
orderByFields: null,
"limit": null,
+ isDistinct: false
});
});
@@ -709,6 +729,7 @@ test('Execute SQL Query with LIMIT clause exceeding total rows', async () => {
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);
});
diff --git a/tests/step-13/index.test.js b/tests/step-13/index.test.js
index 0797faaba..382fcebd7 100644
--- a/tests/step-13/index.test.js
+++ b/tests/step-13/index.test.js
@@ -268,8 +268,9 @@ test('Parse SQL Query', () => {
joinType: null,
groupByFields: null,
hasAggregateWithoutGroupBy: false,
- "orderByFields": null,
- "limit": null
+ orderByFields: null,
+ limit: null,
+ isDistinct: false
});
});
@@ -290,7 +291,8 @@ test('Parse SQL Query with WHERE Clause', () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -315,7 +317,8 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -332,7 +335,8 @@ test('Parse SQL Query with INNER JOIN', async () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
})
});
@@ -349,7 +353,8 @@ test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
})
});
@@ -408,7 +413,8 @@ test('Parse LEFT Join Query Completely', () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
})
})
@@ -425,7 +431,8 @@ test('Parse LEFT Join Query Completely', () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
})
})
@@ -442,7 +449,8 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main tabl
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -459,7 +467,8 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join tabl
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -476,7 +485,8 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main tab
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -493,7 +503,8 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join tab
groupByFields: null,
hasAggregateWithoutGroupBy: false,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -511,7 +522,8 @@ test('Parse COUNT Aggregate Query', () => {
"joinTable": null,
"joinType": null,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -529,7 +541,8 @@ test('Parse SUM Aggregate Query', () => {
"joinTable": null,
"joinType": null,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -546,7 +559,8 @@ test('Parse AVG Aggregate Query', () => {
"joinTable": null,
"joinType": null,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -563,7 +577,8 @@ test('Parse MIN Aggregate Query', () => {
"joinTable": null,
"joinType": null,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -580,7 +595,8 @@ test('Parse MAX Aggregate Query', () => {
"joinTable": null,
"joinType": null,
"orderByFields": null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -597,7 +613,8 @@ test('Parse basic GROUP BY query', () => {
joinCondition: null,
hasAggregateWithoutGroupBy: false,
orderByFields: null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -614,7 +631,8 @@ test('Parse GROUP BY query with WHERE clause', () => {
joinCondition: null,
hasAggregateWithoutGroupBy: false,
orderByFields: null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -631,7 +649,8 @@ test('Parse GROUP BY query with multiple fields', () => {
joinCondition: null,
hasAggregateWithoutGroupBy: false,
orderByFields: null,
- "limit": null
+ "limit": null,
+ isDistinct: false
});
});
@@ -652,6 +671,7 @@ test('Parse GROUP BY query with JOIN and WHERE clauses', () => {
hasAggregateWithoutGroupBy: false,
orderByFields: null,
"limit": null,
+ isDistinct: false
});
});
@@ -716,6 +736,7 @@ 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');
});
From d9019090e988ade54be88655e5fa59b86293ec19 Mon Sep 17 00:00:00 2001
From: sparking_chips
Date: Sun, 14 Apr 2024 12:27:06 +0530
Subject: [PATCH 12/14] test 9 corrected
---
tests/step-09/index.test.js | 27 ++++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/tests/step-09/index.test.js b/tests/step-09/index.test.js
index 1efa5db47..e59d7f25a 100644
--- a/tests/step-09/index.test.js
+++ b/tests/step-09/index.test.js
@@ -21,7 +21,10 @@ test('Parse SQL Query', () => {
groupByFields: null,
hasAggregateWithoutGroupBy: false,
joinTable: null,
- joinCondition: null
+ joinCondition: null,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -50,7 +53,10 @@ test('Parse SQL Query with WHERE Clause', () => {
joinTable: null,
joinType: null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -82,7 +88,10 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
joinTable: null,
joinType: null,
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
});
});
@@ -118,7 +127,10 @@ test('Parse SQL Query with INNER JOIN', async () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
joinType: 'INNER',
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
})
});
@@ -133,7 +145,10 @@ test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => {
joinCondition: { left: 'student.id', right: 'enrollment.student_id' },
joinType: 'INNER',
groupByFields: null,
- hasAggregateWithoutGroupBy: false
+ hasAggregateWithoutGroupBy: false,
+ orderByFields:null,
+ limit: null,
+ isDistinct: false
})
});
@@ -189,6 +204,7 @@ test('Execute SQL Query with LEFT JOIN', async () => {
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 () => {
@@ -198,5 +214,6 @@ test('Execute SQL Query with LEFT JOIN', async () => {
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
From 6ed80f486f0c6731ed6c3c26b1defa8aaaa6c796 Mon Sep 17 00:00:00 2001
From: sparking_chips
Date: Mon, 15 Apr 2024 01:51:17 +0530
Subject: [PATCH 13/14] test 18 done
---
src/csvReader.js | 16 +++-
src/index.js | 80 ++++++++++++-------
src/queryExecutor.js | 21 +++++
src/queryParser.js | 65 +++++++++++----
...xecutor.test.js => deleteExecuter.test.js} | 4 +-
tests/{step-17 => }/insertExecuter.test.js | 4 +-
tests/step-02/index.test.js | 2 +-
tests/step-03/index.test.js | 8 +-
tests/step-04/index.test.js | 10 +--
tests/step-05/index.test.js | 12 +--
tests/step-06/index.test.js | 14 ++--
tests/step-07/index.test.js | 14 ++--
tests/step-08/index.test.js | 18 ++---
tests/step-09/index.test.js | 42 +++-------
tests/step-10/index.test.js | 48 +++++------
tests/step-11/index.test.js | 72 ++++++-----------
tests/step-12/index.test.js | 72 ++++++-----------
tests/step-13/index.test.js | 46 +++++------
tests/step-14/index.test.js | 46 +++++------
tests/step-15/index.test.js | 46 +++++------
tests/step-16/index.test.js | 46 +++++------
tests/step-17/index.test.js | 2 +-
tests/step-18/insertExecuter.test.js | 33 --------
23 files changed, 360 insertions(+), 361 deletions(-)
create mode 100644 src/queryExecutor.js
rename tests/{step-18/deleteExecutor.test.js => deleteExecuter.test.js} (89%)
rename tests/{step-17 => }/insertExecuter.test.js (89%)
delete mode 100644 tests/step-18/insertExecuter.test.js
diff --git a/src/csvReader.js b/src/csvReader.js
index 0b7b54548..bf85aa1da 100644
--- a/src/csvReader.js
+++ b/src/csvReader.js
@@ -1,6 +1,7 @@
// src/csvReader.js
const fs = require('fs');
+const parse = require('json2csv');
const csv = require('csv-parser');
function readCSV(filePath) {
@@ -19,4 +20,17 @@ function readCSV(filePath) {
});
}
-module.exports = readCSV;
\ No newline at end of file
+async function writeCSV(filename, data) {
+ // Convert JSON data to CSV format
+ const csv = parse(data);
+ // Write CSV data to the file
+ try {
+ fs.writeFileSync(filename, csv);
+ console.log(`Data successfully written to ${filename}`);
+ } catch (error) {
+ console.error(`Error writing CSV to ${filename}:`, error);
+ }
+}
+
+module.exports = {readCSV,writeCSV};
+// module.exports = writeCSV;
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 5df6d7876..8b8205a92 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,7 +1,8 @@
// src/index.js
-const {parseQuery} = require('./queryParser');
-const readCSV = require('./csvReader');
+
+const {parseSelectQuery, parseINSERTQuery, parseDeleteQuery} = require('./queryParser');
+const { readCSV, writeCSV } = require('./csvReader');
// Helper functions for different JOIN types
function performInnerJoin(data, joinData, joinCondition, fields, table) {
@@ -59,11 +60,7 @@ function createResultRow(mainRow, joinRow, fields, table, includeAllMainFields)
function performRightJoin(data, joinData, joinCondition, fields, table) {
// Cache the structure of a main table row (keys only)
- console.log("Inside Right join")
- console.log("data",data)
- console.log("Joindata",joinData)
- console.log("JoinCodnitio",joinCondition)
- console.log("fields",fields)
+
const RowStructure = data.length > 0 ? Object.keys(data[0]).reduce((acc, key) => {
acc[key] = null; // Set all values to null initially
return acc;
@@ -79,7 +76,6 @@ function performRightJoin(data, joinData, joinCondition, fields, table) {
// Include all necessary fields from the 'student' table
return createResultRow(mainRowToUse, joinRow, fields, table, true);
});
- console.log("rightJOinedDAta",rightJoinedData)
return rightJoinedData
}
@@ -152,14 +148,10 @@ function applyGroupBy(data, groupByFields, aggregateFunctions) {
async function executeSELECTQuery(query) {
try{
- const { fields, table, whereClauses,joinType, joinTable, joinCondition,groupByFields,hasAggregateWithoutGroupBy,orderByFields,limit,isDistinct } = parseQuery(query);
+ const { fields, table, whereClauses,joinType, joinTable, joinCondition,groupByFields,hasAggregateWithoutGroupBy,orderByFields,limit,isDistinct } = parseSelectQuery(query);
- console.log("join Table",joinTable)
- console.log("table",table)
let data = await readCSV(`${table}.csv`);
- console.log("data before join condition",data)
// LOGIC for applying the joins
- console.log("groupByfieds",groupByFields)
if (joinTable && joinCondition) {
const joinData = await readCSV(`${joinTable}.csv`);
switch (joinType.toUpperCase()) {
@@ -178,11 +170,9 @@ async function executeSELECTQuery(query) {
}
}
- console.log("data",data)
let filteredData = whereClauses.length > 0
? data.filter(row => whereClauses.every(clause => evaluateCondition(row, clause)))
: data;
- console.log("filtered Data after condition",filteredData)
let groupData = filteredData;
if(hasAggregateWithoutGroupBy){
@@ -217,7 +207,6 @@ async function executeSELECTQuery(query) {
return [output];
}else if(groupByFields){
groupData = applyGroupBy(filteredData,groupByFields,fields)
- console.log("Group dataa",groupData)
let orderOutput = groupData;
if(orderByFields){
@@ -229,11 +218,9 @@ async function executeSELECTQuery(query) {
return 0;
});
}
-
if (limit !== null) {
orderOutput = orderOutput.slice(0, limit);
}
-
if (isDistinct) {
groupData = [...new Map(groupData.map(item => [fields.map(field => item[field]).join('|'), item])).values()];
}
@@ -256,7 +243,6 @@ async function executeSELECTQuery(query) {
if (limit !== null) {
orderOutput = orderOutput.slice(0, limit);
}
- console.log("orderOUTput",orderOutput)
if (isDistinct) {
orderOutput = [...new Map(orderOutput.map(item => [fields.map(field => item[field]).join('|'), item])).values()];
}
@@ -265,7 +251,6 @@ async function executeSELECTQuery(query) {
fields.forEach(field => {
selectedRow[field]=row[field];
});
- console.log("final Solution",selectedRow)
return selectedRow;
});
@@ -285,8 +270,12 @@ function evaluateCondition(row, clause) {
// Parse row value and condition value based on their actual types
const rowValue = parsingValue(row[field]);
let conditionValue = parsingValue(value);
- console.log("rowValue",rowValue);
- console.log("conditionValue",conditionValue);
+ if (operator === 'LIKE') {
+ // Transform SQL LIKE pattern to JavaScript RegExp pattern
+ const regexPattern = '^' + value.replace(/%/g, '.*').replace(/_/g, '.') + '$';
+ const regex = new RegExp(regexPattern, 'i'); // 'i' for case-insensitive matching
+ return regex.test(row[field]);
+ }
// Compare the field value with the condition value
switch (operator) {
case '=': return rowValue === conditionValue;
@@ -316,12 +305,45 @@ function parsingValue(value) {
return value;
}
-async function func() {
- 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
+async function executeINSERTQuery(query) {
+ const { table, columns, values } = parseINSERTQuery(query);
+ const data = await readCSV(`${table}.csv`);
- console.log("Result",result)
+ // Creating a fresh row
+ const FRow = {};
+ columns.forEach((column, index) => {
+ let value = values[index];
+ if (value.startsWith("'") && value.endsWith("'")) {
+ value = value.substring(1, value.length - 1);
+ }
+ FRow[column] = value;
+ });
+
+ data.push(FRow);
+
+ await writeCSV(`${table}.csv`, data);
+ return { message: "Row inserted successfully." };
}
-func()
-module.exports = executeSELECTQuery;
\ No newline at end of file
+
+
+// src/queryExecutor.js
+
+async function executeDELETEQuery(query) {
+ const { table, whereClauses } = parseDeleteQuery(query);
+ let data = await readCSV(`${table}.csv`);
+
+ if (whereClauses.length > 0) {
+ // Filter out the rows that meet the where clause conditions
+ // Implement this.
+ } else {
+ // If no where clause, clear the entire table
+ data = [];
+ }
+
+ // Save the updated data back to the CSV file
+ await writeCSV(`${table}.csv`, data);
+
+ return { message: "Rows deleted successfully." };
+}
+
+module.exports = { executeSELECTQuery, executeINSERTQuery, executeDELETEQuery };
\ No newline at end of file
diff --git a/src/queryExecutor.js b/src/queryExecutor.js
new file mode 100644
index 000000000..ca1b2b107
--- /dev/null
+++ b/src/queryExecutor.js
@@ -0,0 +1,21 @@
+// src/queryExecutor.js
+
+async function executeDELETEQuery(query) {
+ const { table, whereClauses } = parseDeleteQuery(query);
+ let data = await readCSV(`${table}.csv`);
+
+ if (whereClauses.length > 0) {
+ // Filter out the rows that meet the where clause conditions
+ // Implement this.
+ } else {
+ // If no where clause, clear the entire table
+ data = [];
+ }
+
+ // Save the updated data back to the CSV file
+ await writeCSV(`${table}.csv`, data);
+
+ return { message: "Rows deleted successfully." };
+}
+
+module.exports = { executeSELECTQuery, executeINSERTQuery, executeDELETEQuery };
\ No newline at end of file
diff --git a/src/queryParser.js b/src/queryParser.js
index 72239e7ff..e321a5a1d 100644
--- a/src/queryParser.js
+++ b/src/queryParser.js
@@ -1,7 +1,7 @@
// src/queryParser.js
-function parseQuery(query) {
+function parseSelectQuery(query) {
// First, let's trim the query to remove any leading/trailing whitespaces
try{
query = query.trim();
@@ -15,19 +15,17 @@ function parseQuery(query) {
isDistinct = true;
query = query.replace('SELECT DISTINCT', 'SELECT');
}
-
const limitMatch = query.match(limitRegex);
let limit = null;
if (limitMatch) {
- limit = parseInt(limitMatch[1]);
+ limit = parseInt(limitMatch[1],10);
query = query.replace(limitRegex,'')
}
console.log("limit",limit)
console.log(typeof(limit))
-
- const orderByMatch = query.match(orderByRegex);
+ const orderByMatch = query.match(orderByRegex);
let orderByFields = null;
if (orderByMatch) {
orderByFields = orderByMatch[1].split(',').map(field => {
@@ -36,8 +34,6 @@ function parseQuery(query) {
});
query = query.replace(orderByRegex, '');
}
-
-
const groupByMatch = query.match(groupByRegex);
// Initialize variables for different parts of the query
let selectPart, fromPart;
@@ -51,8 +47,7 @@ function parseQuery(query) {
if (whereClause && whereClause.includes('GROUP BY')) {
whereClause = whereClause.split(/\sGROUP\sBY\s/i)[0].trim();
}
-
-
+console.log(whereClause)
// 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
@@ -102,7 +97,7 @@ if (whereClause && whereClause.includes('GROUP BY')) {
if (hasAggregateFunction && !groupByMatch) {
hasAggregateWithoutGroupBy = true;
}
-
+ console.log("where clausese",whereClauses)
return {
fields: fields.split(',').map(field => field.trim()),
table: table.trim(),
@@ -116,27 +111,67 @@ if (whereClause && whereClause.includes('GROUP BY')) {
limit,
isDistinct
};
-
}
catch(error){
console.log(error)
throw new Error(`Query parsing error: ${error.message}`)
}
+}
+function parseDeleteQuery(query){
+ // const deleteRegex = /^DELETE\s+FROM\s+\w+(\s+WHERE\s+.+)?;?$/i;
+ const deleteRegex = /DELETE FROM (\w+)( WHERE (.*))?/i;
+ const match = query.match(deleteRegex);
+ if (!match) {
+ throw new Error("Wrong DELETE syntax.");
+ }
+ const [, table, , whereString] = match;
+ let whereClauses = [];
+ if (whereString) {
+ whereClauses = parseWhereClause(whereString);
+ }
+
+ return {
+ type: 'DELETE',
+ table: table.trim(),
+ whereClauses
+ };
}
// src/queryParser.js
function parseWhereClause(whereString) {
- const conditionRegex = /(.*?)(=|!=|>|<|>=|<=)(.*)/;
+ const conditionRegex =/(.*?)(=|!=|>|<|>=|<=)(.*)/;
return whereString.split(/ AND | OR /i).map(conditionString => {
+ if (conditionString.includes(' LIKE '))
+ {
+ const [field, pattern] = conditionString.split(/\sLIKE\s/i);
+ return { field: field.trim(), operator: 'LIKE', value: pattern.trim().replace(/^'(.*)'$/, '$1') };
+ }else{
const match = conditionString.match(conditionRegex);
if (match) {
const [, field, operator, value] = match;
return { field: field.trim(), operator, value: value.trim() };
}
throw new Error('Invalid WHERE clause format');
+ }
});
+}
+
+function parseINSERTQuery(query){
+ const insertRegex = /INSERT\s+INTO\s+([^\s\(]+)\s*\(([^)]+)\)\s*VALUES\s*\(([^)]+)\)/i;
+ const match = query.match(insertRegex)
+
+ if(!match){
+ throw new error("Wrong INSERT INTO syntax")
+ }
+ const [, table, columns, values] = match;
+ return {
+ type:'INSERT',
+ table:table.trim(),
+ columns:columns.split(',').map(column => column.trim()),
+ values: values.split(',').map(value => value.trim())
+ }
}
function parseJoinClause(query) {
@@ -161,8 +196,8 @@ function parseJoinClause(query) {
};
}
-const query = 'SELECT id, name FROM student ORDER BY age DESC LIMIT 2';
-const res = parseQuery(query)
+const query = "SELECT DISTINCT name FROM student WHERE name LIKE '%e%";
+const res = parseSelectQuery(query)
-module.exports = {parseQuery,parseJoinClause};
\ No newline at end of file
+module.exports = {parseSelectQuery, parseDeleteQuery,parseJoinClause, parseINSERTQuery};
\ No newline at end of file
diff --git a/tests/step-18/deleteExecutor.test.js b/tests/deleteExecuter.test.js
similarity index 89%
rename from tests/step-18/deleteExecutor.test.js
rename to tests/deleteExecuter.test.js
index 11ae617b7..f7c3eb5ae 100644
--- a/tests/step-18/deleteExecutor.test.js
+++ b/tests/deleteExecuter.test.js
@@ -1,5 +1,5 @@
-const { executeDELETEQuery } = require('../../src/index');
-const { readCSV, writeCSV } = require('../../src/csvReader');
+const { executeDELETEQuery } = require('../src/queryExecutor');
+const { readCSV, writeCSV } = require('../src/csvReader');
const fs = require('fs');
// Helper function to create courses.csv with initial data
diff --git a/tests/step-17/insertExecuter.test.js b/tests/insertExecuter.test.js
similarity index 89%
rename from tests/step-17/insertExecuter.test.js
rename to tests/insertExecuter.test.js
index 8c405f727..0e27265a3 100644
--- a/tests/step-17/insertExecuter.test.js
+++ b/tests/insertExecuter.test.js
@@ -1,5 +1,5 @@
-const { executeINSERTQuery } = require('../../src/index');
-const { readCSV, writeCSV } = require('../../src/csvReader');
+const { executeINSERTQuery } = require('../src/queryExecutor');
+const { readCSV, writeCSV } = require('../src/csvReader');
const fs = require('fs');
// Helper function to create grades.csv with initial data
diff --git a/tests/step-02/index.test.js b/tests/step-02/index.test.js
index d9300b8f4..59a3322e8 100644
--- a/tests/step-02/index.test.js
+++ b/tests/step-02/index.test.js
@@ -1,4 +1,4 @@
-const readCSV = require('../../src/csvReader');
+const {readCSV} = require('../../src/csvReader');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
diff --git a/tests/step-03/index.test.js b/tests/step-03/index.test.js
index 12727913f..b5cf79c0a 100644
--- a/tests/step-03/index.test.js
+++ b/tests/step-03/index.test.js
@@ -1,5 +1,5 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery} = require('../../src/queryParser');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery} = require('../../src/queryParser');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -11,7 +11,7 @@ test('Read CSV File', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -25,5 +25,5 @@ test('Parse SQL Query', () => {
limit: null,
isDistinct: false
});
-
+
});
\ No newline at end of file
diff --git a/tests/step-04/index.test.js b/tests/step-04/index.test.js
index 06b1852fc..1ba20fcac 100644
--- a/tests/step-04/index.test.js
+++ b/tests/step-04/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -12,7 +12,7 @@ test('Read CSV File', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -26,7 +26,7 @@ test('Parse SQL Query', () => {
limit: null,
isDistinct: false
});
-
+
});
test('Execute SQL Query', async () => {
diff --git a/tests/step-05/index.test.js b/tests/step-05/index.test.js
index d7101520b..abb8ce0f7 100644
--- a/tests/step-05/index.test.js
+++ b/tests/step-05/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -12,7 +12,7 @@ test('Read CSV File', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -40,7 +40,7 @@ test('Execute SQL Query', async () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -59,7 +59,7 @@ test('Parse SQL Query with WHERE Clause', () => {
limit: null,
isDistinct: false
});
-
+
});
test('Execute SQL Query with WHERE Clause', async () => {
diff --git a/tests/step-06/index.test.js b/tests/step-06/index.test.js
index cc6ec58ec..2751391a8 100644
--- a/tests/step-06/index.test.js
+++ b/tests/step-06/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -12,7 +12,7 @@ test('Read CSV File', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM sample';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'sample',
@@ -40,7 +40,7 @@ test('Execute SQL Query', async () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -71,7 +71,7 @@ test('Execute SQL Query with WHERE Clause', async () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -93,7 +93,7 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
limit: null,
isDistinct: false
});
-
+
});
test('Execute SQL Query with Multiple WHERE Clause', async () => {
diff --git a/tests/step-07/index.test.js b/tests/step-07/index.test.js
index 6af237b03..156b6df17 100644
--- a/tests/step-07/index.test.js
+++ b/tests/step-07/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -12,7 +12,7 @@ test('Read CSV File', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM sample';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'sample',
@@ -40,7 +40,7 @@ test('Execute SQL Query', async () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -71,7 +71,7 @@ test('Execute SQL Query with WHERE Clause', async () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -107,7 +107,7 @@ test('Execute SQL Query with Greater Than', async () => {
const result = await executeSELECTQuery(queryWithGT);
expect(result.length).toEqual(3);
expect(result[0]).toHaveProperty('id');
-
+
});
test('Execute SQL Query with Not Equal to', async () => {
diff --git a/tests/step-08/index.test.js b/tests/step-08/index.test.js
index a020891de..6bf56b3e7 100644
--- a/tests/step-08/index.test.js
+++ b/tests/step-08/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -12,7 +12,7 @@ test('Read CSV File', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -40,7 +40,7 @@ test('Execute SQL Query', async () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -71,7 +71,7 @@ test('Execute SQL Query with WHERE Clause', async () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -118,7 +118,7 @@ test('Execute SQL Query with Not Equal to', async () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -136,7 +136,7 @@ test('Parse SQL Query with INNER JOIN', async () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -213,6 +213,6 @@ test('Execute SQL Query with LEFT JOIN', async () => {
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
diff --git a/tests/step-09/index.test.js b/tests/step-09/index.test.js
index e59d7f25a..b065dab20 100644
--- a/tests/step-09/index.test.js
+++ b/tests/step-09/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -12,7 +12,7 @@ test('Read CSV File', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -40,7 +40,7 @@ test('Execute SQL Query', async () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -71,7 +71,7 @@ test('Execute SQL Query with WHERE Clause', async () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -118,7 +118,7 @@ test('Execute SQL Query with Not Equal to', async () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -136,7 +136,7 @@ test('Parse SQL Query with INNER JOIN', async () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -155,14 +155,7 @@ test('Parse SQL Query with INNER JOIN and WHERE Clause', async () => {
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' },
- { 'student.name': 'Jane', 'enrollment.course': 'Chemistry' },
- { '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({
@@ -174,20 +167,7 @@ test('Execute SQL Query with INNER JOIN', async () => {
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({
@@ -214,6 +194,6 @@ test('Execute SQL Query with LEFT JOIN', async () => {
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
diff --git a/tests/step-10/index.test.js b/tests/step-10/index.test.js
index bcc490d33..30521ea39 100644
--- a/tests/step-10/index.test.js
+++ b/tests/step-10/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery, parseJoinClause} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery, parseJoinClause} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -258,7 +258,7 @@ test('Average age of students above a certain age', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -276,7 +276,7 @@ test('Parse SQL Query', () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -298,7 +298,7 @@ test('Parse SQL Query with WHERE Clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -324,7 +324,7 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -342,7 +342,7 @@ test('Parse SQL Query with INNER JOIN', async () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -402,7 +402,7 @@ test('Returns null for queries without JOIN', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -420,7 +420,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -438,7 +438,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -456,7 +456,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -474,7 +474,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -492,7 +492,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main tab
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -511,7 +511,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join tab
test('Parse COUNT Aggregate Query', () => {
const query = 'SELECT COUNT(*) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['COUNT(*)'],
table: 'student',
@@ -530,7 +530,7 @@ test('Parse COUNT Aggregate Query', () => {
test('Parse SUM Aggregate Query', () => {
const query = 'SELECT SUM(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['SUM(age)'],
table: 'student',
@@ -548,7 +548,7 @@ test('Parse SUM Aggregate Query', () => {
test('Parse AVG Aggregate Query', () => {
const query = 'SELECT AVG(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['AVG(age)'],
table: 'student',
@@ -566,7 +566,7 @@ test('Parse AVG Aggregate Query', () => {
test('Parse MIN Aggregate Query', () => {
const query = 'SELECT MIN(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MIN(age)'],
table: 'student',
@@ -584,7 +584,7 @@ test('Parse MIN Aggregate Query', () => {
test('Parse MAX Aggregate Query', () => {
const query = 'SELECT MAX(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MAX(age)'],
table: 'student',
@@ -602,7 +602,7 @@ test('Parse MAX Aggregate Query', () => {
test('Parse basic GROUP BY query', () => {
const query = 'SELECT age, COUNT(*) FROM student GROUP BY age';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -620,7 +620,7 @@ test('Parse basic GROUP BY query', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -638,7 +638,7 @@ test('Parse GROUP BY query with WHERE clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student_id', 'course', 'COUNT(*)'],
table: 'enrollment',
@@ -652,12 +652,12 @@ test('Parse GROUP BY query with multiple fields', () => {
"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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student.name', 'COUNT(*)'],
table: 'student',
diff --git a/tests/step-11/index.test.js b/tests/step-11/index.test.js
index 6462b3d6e..4a134e8dc 100644
--- a/tests/step-11/index.test.js
+++ b/tests/step-11/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery, parseJoinClause} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery, parseJoinClause} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -53,14 +53,7 @@ test('Execute SQL Query with Not Equal to', async () => {
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' },
- { 'student.name': 'Jane', 'enrollment.course': 'Chemistry' },
- { '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({
@@ -72,20 +65,7 @@ test('Execute SQL Query with INNER JOIN', async () => {
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({
@@ -258,7 +238,7 @@ test('Average age of students above a certain age', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -276,7 +256,7 @@ test('Parse SQL Query', () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -298,7 +278,7 @@ test('Parse SQL Query with WHERE Clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -324,7 +304,7 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -342,7 +322,7 @@ test('Parse SQL Query with INNER JOIN', async () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -402,7 +382,7 @@ test('Returns null for queries without JOIN', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -420,7 +400,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -438,7 +418,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -456,7 +436,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -474,7 +454,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -492,7 +472,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main tab
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -511,7 +491,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join tab
test('Parse COUNT Aggregate Query', () => {
const query = 'SELECT COUNT(*) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['COUNT(*)'],
table: 'student',
@@ -530,7 +510,7 @@ test('Parse COUNT Aggregate Query', () => {
test('Parse SUM Aggregate Query', () => {
const query = 'SELECT SUM(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['SUM(age)'],
table: 'student',
@@ -548,7 +528,7 @@ test('Parse SUM Aggregate Query', () => {
test('Parse AVG Aggregate Query', () => {
const query = 'SELECT AVG(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['AVG(age)'],
table: 'student',
@@ -566,7 +546,7 @@ test('Parse AVG Aggregate Query', () => {
test('Parse MIN Aggregate Query', () => {
const query = 'SELECT MIN(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MIN(age)'],
table: 'student',
@@ -584,7 +564,7 @@ test('Parse MIN Aggregate Query', () => {
test('Parse MAX Aggregate Query', () => {
const query = 'SELECT MAX(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MAX(age)'],
table: 'student',
@@ -602,8 +582,8 @@ test('Parse MAX Aggregate Query', () => {
test('Parse basic GROUP BY query', () => {
const query = 'SELECT age, COUNT(*) FROM student GROUP BY age';
- const parsed = parseQuery(query);
-
+ const parsed = parseSelectQuery(query);
+
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -621,7 +601,7 @@ test('Parse basic GROUP BY query', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -639,7 +619,7 @@ test('Parse GROUP BY query with WHERE clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student_id', 'course', 'COUNT(*)'],
table: 'enrollment',
@@ -657,7 +637,7 @@ test('Parse GROUP BY query with multiple fields', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student.name', 'COUNT(*)'],
table: 'student',
diff --git a/tests/step-12/index.test.js b/tests/step-12/index.test.js
index 29b05003d..7a0dd83f1 100644
--- a/tests/step-12/index.test.js
+++ b/tests/step-12/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery, parseJoinClause} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery, parseJoinClause} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -53,14 +53,7 @@ test('Execute SQL Query with Not Equal to', async () => {
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' },
- { 'student.name': 'Jane', 'enrollment.course': 'Chemistry' },
- { '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({
@@ -72,20 +65,7 @@ test('Execute SQL Query with INNER JOIN', async () => {
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({
@@ -258,7 +238,7 @@ test('Average age of students above a certain age', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -276,7 +256,7 @@ test('Parse SQL Query', () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -298,7 +278,7 @@ test('Parse SQL Query with WHERE Clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -324,7 +304,7 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -342,7 +322,7 @@ test('Parse SQL Query with INNER JOIN', async () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -402,7 +382,7 @@ test('Returns null for queries without JOIN', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -420,7 +400,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -438,7 +418,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -456,7 +436,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -474,7 +454,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -492,7 +472,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main tab
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -511,7 +491,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join tab
test('Parse COUNT Aggregate Query', () => {
const query = 'SELECT COUNT(*) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['COUNT(*)'],
table: 'student',
@@ -530,7 +510,7 @@ test('Parse COUNT Aggregate Query', () => {
test('Parse SUM Aggregate Query', () => {
const query = 'SELECT SUM(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['SUM(age)'],
table: 'student',
@@ -548,7 +528,7 @@ test('Parse SUM Aggregate Query', () => {
test('Parse AVG Aggregate Query', () => {
const query = 'SELECT AVG(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['AVG(age)'],
table: 'student',
@@ -566,7 +546,7 @@ test('Parse AVG Aggregate Query', () => {
test('Parse MIN Aggregate Query', () => {
const query = 'SELECT MIN(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MIN(age)'],
table: 'student',
@@ -584,7 +564,7 @@ test('Parse MIN Aggregate Query', () => {
test('Parse MAX Aggregate Query', () => {
const query = 'SELECT MAX(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MAX(age)'],
table: 'student',
@@ -602,7 +582,7 @@ test('Parse MAX Aggregate Query', () => {
test('Parse basic GROUP BY query', () => {
const query = 'SELECT age, COUNT(*) FROM student GROUP BY age';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -620,7 +600,7 @@ test('Parse basic GROUP BY query', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -638,7 +618,7 @@ test('Parse GROUP BY query with WHERE clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student_id', 'course', 'COUNT(*)'],
table: 'enrollment',
@@ -656,7 +636,7 @@ test('Parse GROUP BY query with multiple fields', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student.name', 'COUNT(*)'],
table: 'student',
@@ -729,7 +709,7 @@ test('Execute SQL Query with LIMIT clause exceeding total rows', async () => {
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);
});
diff --git a/tests/step-13/index.test.js b/tests/step-13/index.test.js
index 382fcebd7..f230648e2 100644
--- a/tests/step-13/index.test.js
+++ b/tests/step-13/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery, parseJoinClause} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery, parseJoinClause} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -258,7 +258,7 @@ test('Average age of students above a certain age', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -276,7 +276,7 @@ test('Parse SQL Query', () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -298,7 +298,7 @@ test('Parse SQL Query with WHERE Clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -324,7 +324,7 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -342,7 +342,7 @@ test('Parse SQL Query with INNER JOIN', async () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -402,7 +402,7 @@ test('Returns null for queries without JOIN', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -420,7 +420,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -438,7 +438,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -456,7 +456,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -474,7 +474,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -492,7 +492,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main tab
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -511,7 +511,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join tab
test('Parse COUNT Aggregate Query', () => {
const query = 'SELECT COUNT(*) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['COUNT(*)'],
table: 'student',
@@ -530,7 +530,7 @@ test('Parse COUNT Aggregate Query', () => {
test('Parse SUM Aggregate Query', () => {
const query = 'SELECT SUM(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['SUM(age)'],
table: 'student',
@@ -548,7 +548,7 @@ test('Parse SUM Aggregate Query', () => {
test('Parse AVG Aggregate Query', () => {
const query = 'SELECT AVG(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['AVG(age)'],
table: 'student',
@@ -566,7 +566,7 @@ test('Parse AVG Aggregate Query', () => {
test('Parse MIN Aggregate Query', () => {
const query = 'SELECT MIN(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MIN(age)'],
table: 'student',
@@ -584,7 +584,7 @@ test('Parse MIN Aggregate Query', () => {
test('Parse MAX Aggregate Query', () => {
const query = 'SELECT MAX(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MAX(age)'],
table: 'student',
@@ -602,7 +602,7 @@ test('Parse MAX Aggregate Query', () => {
test('Parse basic GROUP BY query', () => {
const query = 'SELECT age, COUNT(*) FROM student GROUP BY age';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -620,7 +620,7 @@ test('Parse basic GROUP BY query', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -638,7 +638,7 @@ test('Parse GROUP BY query with WHERE clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student_id', 'course', 'COUNT(*)'],
table: 'enrollment',
@@ -656,7 +656,7 @@ test('Parse GROUP BY query with multiple fields', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student.name', 'COUNT(*)'],
table: 'student',
diff --git a/tests/step-14/index.test.js b/tests/step-14/index.test.js
index 502411fa7..ad0c833b6 100644
--- a/tests/step-14/index.test.js
+++ b/tests/step-14/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery, parseJoinClause} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery, parseJoinClause} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -258,7 +258,7 @@ test('Average age of students above a certain age', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -276,7 +276,7 @@ test('Parse SQL Query', () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -298,7 +298,7 @@ test('Parse SQL Query with WHERE Clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -324,7 +324,7 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -342,7 +342,7 @@ test('Parse SQL Query with INNER JOIN', async () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -402,7 +402,7 @@ test('Returns null for queries without JOIN', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -420,7 +420,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -438,7 +438,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -456,7 +456,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -474,7 +474,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -492,7 +492,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main tab
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -511,7 +511,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join tab
test('Parse COUNT Aggregate Query', () => {
const query = 'SELECT COUNT(*) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['COUNT(*)'],
table: 'student',
@@ -530,7 +530,7 @@ test('Parse COUNT Aggregate Query', () => {
test('Parse SUM Aggregate Query', () => {
const query = 'SELECT SUM(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['SUM(age)'],
table: 'student',
@@ -548,7 +548,7 @@ test('Parse SUM Aggregate Query', () => {
test('Parse AVG Aggregate Query', () => {
const query = 'SELECT AVG(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['AVG(age)'],
table: 'student',
@@ -566,7 +566,7 @@ test('Parse AVG Aggregate Query', () => {
test('Parse MIN Aggregate Query', () => {
const query = 'SELECT MIN(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MIN(age)'],
table: 'student',
@@ -584,7 +584,7 @@ test('Parse MIN Aggregate Query', () => {
test('Parse MAX Aggregate Query', () => {
const query = 'SELECT MAX(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MAX(age)'],
table: 'student',
@@ -602,7 +602,7 @@ test('Parse MAX Aggregate Query', () => {
test('Parse basic GROUP BY query', () => {
const query = 'SELECT age, COUNT(*) FROM student GROUP BY age';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -620,7 +620,7 @@ test('Parse basic GROUP BY query', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -638,7 +638,7 @@ test('Parse GROUP BY query with WHERE clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student_id', 'course', 'COUNT(*)'],
table: 'enrollment',
@@ -656,7 +656,7 @@ test('Parse GROUP BY query with multiple fields', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student.name', 'COUNT(*)'],
table: 'student',
diff --git a/tests/step-15/index.test.js b/tests/step-15/index.test.js
index a2aa4daee..677646807 100644
--- a/tests/step-15/index.test.js
+++ b/tests/step-15/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery, parseJoinClause} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery, parseJoinClause} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -258,7 +258,7 @@ test('Average age of students above a certain age', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -276,7 +276,7 @@ test('Parse SQL Query', () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -298,7 +298,7 @@ test('Parse SQL Query with WHERE Clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -324,7 +324,7 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -342,7 +342,7 @@ test('Parse SQL Query with INNER JOIN', async () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -402,7 +402,7 @@ test('Returns null for queries without JOIN', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -420,7 +420,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -438,7 +438,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -456,7 +456,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -474,7 +474,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -492,7 +492,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main tab
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -511,7 +511,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join tab
test('Parse COUNT Aggregate Query', () => {
const query = 'SELECT COUNT(*) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['COUNT(*)'],
table: 'student',
@@ -530,7 +530,7 @@ test('Parse COUNT Aggregate Query', () => {
test('Parse SUM Aggregate Query', () => {
const query = 'SELECT SUM(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['SUM(age)'],
table: 'student',
@@ -548,7 +548,7 @@ test('Parse SUM Aggregate Query', () => {
test('Parse AVG Aggregate Query', () => {
const query = 'SELECT AVG(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['AVG(age)'],
table: 'student',
@@ -566,7 +566,7 @@ test('Parse AVG Aggregate Query', () => {
test('Parse MIN Aggregate Query', () => {
const query = 'SELECT MIN(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MIN(age)'],
table: 'student',
@@ -584,7 +584,7 @@ test('Parse MIN Aggregate Query', () => {
test('Parse MAX Aggregate Query', () => {
const query = 'SELECT MAX(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MAX(age)'],
table: 'student',
@@ -602,7 +602,7 @@ test('Parse MAX Aggregate Query', () => {
test('Parse basic GROUP BY query', () => {
const query = 'SELECT age, COUNT(*) FROM student GROUP BY age';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -620,7 +620,7 @@ test('Parse basic GROUP BY query', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -638,7 +638,7 @@ test('Parse GROUP BY query with WHERE clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student_id', 'course', 'COUNT(*)'],
table: 'enrollment',
@@ -656,7 +656,7 @@ test('Parse GROUP BY query with multiple fields', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student.name', 'COUNT(*)'],
table: 'student',
diff --git a/tests/step-16/index.test.js b/tests/step-16/index.test.js
index a2aa4daee..677646807 100644
--- a/tests/step-16/index.test.js
+++ b/tests/step-16/index.test.js
@@ -1,6 +1,6 @@
-const readCSV = require('../../src/csvReader');
-const {parseQuery, parseJoinClause} = require('../../src/queryParser');
-const executeSELECTQuery = require('../../src/index');
+const {readCSV} = require('../../src/csvReader');
+const {parseSelectQuery, parseJoinClause} = require('../../src/queryParser');
+const {executeSELECTQuery} = require('../../src/index');
test('Read CSV File', async () => {
const data = await readCSV('./student.csv');
@@ -258,7 +258,7 @@ test('Average age of students above a certain age', async () => {
test('Parse SQL Query', () => {
const query = 'SELECT id, name FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -276,7 +276,7 @@ test('Parse SQL Query', () => {
test('Parse SQL Query with WHERE Clause', () => {
const query = 'SELECT id, name FROM student WHERE age = 25';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -298,7 +298,7 @@ test('Parse SQL Query with WHERE Clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['id', 'name'],
table: 'student',
@@ -324,7 +324,7 @@ test('Parse SQL Query with Multiple WHERE Clauses', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -342,7 +342,7 @@ test('Parse SQL Query with INNER JOIN', async () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -402,7 +402,7 @@ test('Returns null for queries without JOIN', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -420,7 +420,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = parseSelectQuery(query);
expect(result).toEqual({
fields: ['student.name', 'enrollment.course'],
table: 'student',
@@ -438,7 +438,7 @@ test('Parse LEFT Join Query Completely', () => {
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -456,7 +456,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the main tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -474,7 +474,7 @@ test('Parse SQL Query with LEFT JOIN with a WHERE clause filtering the join tabl
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -492,7 +492,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the main tab
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);
+ const result = await parseSelectQuery(query);
expect(result).toEqual({
"fields": ["student.name", "enrollment.course"],
"joinCondition": { "left": "student.id", "right": "enrollment.student_id" },
@@ -511,7 +511,7 @@ test('Parse SQL Query with RIGHT JOIN with a WHERE clause filtering the join tab
test('Parse COUNT Aggregate Query', () => {
const query = 'SELECT COUNT(*) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['COUNT(*)'],
table: 'student',
@@ -530,7 +530,7 @@ test('Parse COUNT Aggregate Query', () => {
test('Parse SUM Aggregate Query', () => {
const query = 'SELECT SUM(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['SUM(age)'],
table: 'student',
@@ -548,7 +548,7 @@ test('Parse SUM Aggregate Query', () => {
test('Parse AVG Aggregate Query', () => {
const query = 'SELECT AVG(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['AVG(age)'],
table: 'student',
@@ -566,7 +566,7 @@ test('Parse AVG Aggregate Query', () => {
test('Parse MIN Aggregate Query', () => {
const query = 'SELECT MIN(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MIN(age)'],
table: 'student',
@@ -584,7 +584,7 @@ test('Parse MIN Aggregate Query', () => {
test('Parse MAX Aggregate Query', () => {
const query = 'SELECT MAX(age) FROM student';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['MAX(age)'],
table: 'student',
@@ -602,7 +602,7 @@ test('Parse MAX Aggregate Query', () => {
test('Parse basic GROUP BY query', () => {
const query = 'SELECT age, COUNT(*) FROM student GROUP BY age';
- const parsed = parseQuery(query);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -620,7 +620,7 @@ test('Parse basic GROUP BY query', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['age', 'COUNT(*)'],
table: 'student',
@@ -638,7 +638,7 @@ test('Parse GROUP BY query with WHERE clause', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student_id', 'course', 'COUNT(*)'],
table: 'enrollment',
@@ -656,7 +656,7 @@ test('Parse GROUP BY query with multiple fields', () => {
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);
+ const parsed = parseSelectQuery(query);
expect(parsed).toEqual({
fields: ['student.name', 'COUNT(*)'],
table: 'student',
diff --git a/tests/step-17/index.test.js b/tests/step-17/index.test.js
index c99d01fbb..02d6b479f 100644
--- a/tests/step-17/index.test.js
+++ b/tests/step-17/index.test.js
@@ -1,4 +1,4 @@
-const {readCSV} = require('../../src/csvReader');
+const {readCSV,writeCSV} = require('../../src/csvReader');
const {executeSELECTQuery } = require('../../src/index');
const { parseJoinClause, parseSelectQuery } = require('../../src/queryParser');
diff --git a/tests/step-18/insertExecuter.test.js b/tests/step-18/insertExecuter.test.js
deleted file mode 100644
index 8c405f727..000000000
--- a/tests/step-18/insertExecuter.test.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const { executeINSERTQuery } = require('../../src/index');
-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');
- console.log(updatedData)
- expect(newEntry).toBeDefined();
- expect(newEntry.grade).toEqual('A');
-
- // Cleanup: Delete grades.csv
- fs.unlinkSync('grades.csv');
-});
\ No newline at end of file
From a8aae0bc2adbb8ed6ecf502861be6383a35ad0aa Mon Sep 17 00:00:00 2001
From: sparking_chips
Date: Mon, 15 Apr 2024 02:28:01 +0530
Subject: [PATCH 14/14] test 20 done
---
cli.js | 33 +++
tests/step-19/cli.js => cli.test.js | 11 +-
src/index.js | 345 +--------------------------
src/queryExecutor.js | 328 +++++++++++++++++++++++++
tests/step-19/deleteExecutor.test.js | 31 ---
tests/step-19/insertExecuter.test.js | 33 ---
tests/step-20/cli.js | 53 ----
tests/step-20/deleteExecutor.test.js | 31 ---
tests/step-20/insertExecuter.test.js | 33 ---
9 files changed, 367 insertions(+), 531 deletions(-)
create mode 100644 cli.js
rename tests/step-19/cli.js => cli.test.js (74%)
delete mode 100644 tests/step-19/deleteExecutor.test.js
delete mode 100644 tests/step-19/insertExecuter.test.js
delete mode 100644 tests/step-20/cli.js
delete mode 100644 tests/step-20/deleteExecutor.test.js
delete mode 100644 tests/step-20/insertExecuter.test.js
diff --git a/cli.js b/cli.js
new file mode 100644
index 000000000..1594a0030
--- /dev/null
+++ b/cli.js
@@ -0,0 +1,33 @@
+#!/usr/bin/env node
+
+
+const readline = require('readline');
+const { executeSELECTQuery, executeINSERTQuery, executeDELETEQuery } = require('./queryExecutor');
+
+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
+ }catch (error) {
+ console.error('Error:', error.message);
+ }
+
+ rl.prompt();
+}).on('close', () => {
+ console.log('Exiting SQL CLI');
+ process.exit(0);
+});
\ No newline at end of file
diff --git a/tests/step-19/cli.js b/cli.test.js
similarity index 74%
rename from tests/step-19/cli.js
rename to cli.test.js
index fbba6c02c..5d222e6c5 100644
--- a/tests/step-19/cli.js
+++ b/cli.test.js
@@ -20,24 +20,21 @@ test('DISTINCT with Multiple Columns via CLI', (done) => {
match[1] = match[1].replace(/'/g, '"').replace(/(\w+):/g, '"$1":');
if (match && match[1]) {
- console.log(match[1]);
- console.log(typeof match[1])
// Parse the captured JSON string
- // const results = JSON.parse(match[1]);
+ const results = JSON.parse(match[1]);
// Validation logic
- expect(JSON.parse(match[1])).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\" } ]")
- ([
+ 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' },
+ { student_id: '5', course: 'Physics' }
]);
console.log("Test passed successfully");
} else {
- done()
- throw new Error('Failed to parse CLI output');
+ throw new Error('Failed to parse CLI output');
}
done();
diff --git a/src/index.js b/src/index.js
index 8b8205a92..dfab77585 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,349 +1,8 @@
// src/index.js
-
+const { executeSELECTQuery, executeINSERTQuery, executeDELETEQuery } = require('./queryExecutor');
const {parseSelectQuery, parseINSERTQuery, parseDeleteQuery} = require('./queryParser');
const { readCSV, writeCSV } = require('./csvReader');
-// Helper functions for different JOIN types
-function performInnerJoin(data, joinData, joinCondition, fields, table) {
- return data.flatMap(mainRow => {
- const matchedJoinRows = joinData.filter(joinRow => {
- const mainValue = mainRow[joinCondition.left.split('.')[1]];
- const joinValue = joinRow[joinCondition.right.split('.')[1]];
- return mainValue === joinValue;
- });
-
- // If there are matching rows, create a row for each match
- return matchedJoinRows.map(joinRow => {
- return fields.reduce((acc, field) => {
- const [tableName, fieldName] = field.split('.');
- acc[field] = tableName === table ? mainRow[fieldName] : joinRow[fieldName];
- return acc;
- }, {});
- });
- });
-}
-
-function performLeftJoin(data, joinData, joinCondition, fields, table) {
- const leftJoinedData = data.flatMap(mainRow => {
- const matchedJoinRows = joinData.filter(joinRow => {
- const mainValue = mainRow[joinCondition.left.split('.')[1]];
- const joinValue = joinRow[joinCondition.right.split('.')[1]];
- return mainValue === joinValue;
- });
-
- if (matchedJoinRows.length === 0) {
- return [createResultRow(mainRow, null, fields, table, true)];
- }
- return matchedJoinRows.map(joinRow => createResultRow(mainRow, joinRow, fields, table, true));
-
- });
- return leftJoinedData;
-}
-
-function createResultRow(mainRow, joinRow, fields, table, includeAllMainFields) {
- const resultRow = {};
- if (includeAllMainFields) {
- // Include all fields from the main table
- Object.keys(mainRow || {}).forEach(key => {
- const prefixedKey = `${table}.${key}`;
- resultRow[prefixedKey] = mainRow ? mainRow[key] : null;
- });
- }
- // Now, add or overwrite with the fields specified in the query
- fields.forEach(field => {
- const [tableName, fieldName] = field.includes('.') ? field.split('.') : [table, field];
- resultRow[field] = tableName === table && mainRow ? mainRow[fieldName] : joinRow ? joinRow[fieldName] : null;
- });
- return resultRow;
-}
-
-function performRightJoin(data, joinData, joinCondition, fields, table) {
- // Cache the structure of a main table row (keys only)
-
- const RowStructure = data.length > 0 ? Object.keys(data[0]).reduce((acc, key) => {
- acc[key] = null; // Set all values to null initially
- return acc;
- }, {}) : {};
- let rightJoinedData = joinData.map(joinRow => {
- const mainRowMatch = data.find(mainRow => {
- const mainValue = getValueFromGivenRow(mainRow, joinCondition.left);
- const joinValue = getValueFromGivenRow(joinRow, joinCondition.right);
- return mainValue === joinValue;
- });
- // Use the cached structure if no match is found
- const mainRowToUse = mainRowMatch || RowStructure;
- // Include all necessary fields from the 'student' table
- return createResultRow(mainRowToUse, joinRow, fields, table, true);
- });
- return rightJoinedData
-}
-
-function getValueFromGivenRow(row, compoundFieldName) {
- const [tableName, fieldName] = compoundFieldName.split('.');
- return row[`${tableName}.${fieldName}`] || row[fieldName];
-}
-
-function applyGroupBy(data, groupByFields, aggregateFunctions) {
- const groupResult = {};
- data.forEach(row => {
- // Generate a key for the group
- const Key = groupByFields.map(field => row[field]).join('-');
- // Initialize group in results if it doesn't exist
- if (!groupResult[Key]) {
- groupResult[Key] = { count: 0, sums: {}, mins: {}, maxes: {} };
- groupByFields.forEach(field => groupResult[Key][field] = row[field]);
- }
- // Aggregate calculations
- groupResult[Key].count += 1;
- aggregateFunctions.forEach(func => {
- const match = /(\w+)\((\w+)\)/.exec(func);
- if (match) {
- const [, aggregateFunc, aggregateField] = match;
- const value = parseFloat(row[aggregateField]);
- switch (aggregateFunc.toUpperCase()) {
- case 'SUM':
- groupResult[Key].sums[aggregateField] = (groupResult[Key].sums[aggregateField] || 0) + value;
- break;
- case 'MIN':
- groupResult[Key].mins[aggregateField] = Math.min(groupResult[Key].mins[aggregateField] || value, value);
- break;
- case 'MAX':
- groupResult[Key].maxes[aggregateField] = Math.max(groupResult[Key].maxes[aggregateField] || value, value);
- break;
- // Additional aggregate functions can be added here
- }
- }
- });
- });
- // Convert grouped results into an array format
- return Object.values(groupResult).map(group => {
- // Construct the final grouped object based on required fields
- const finalGroup = {};
- groupByFields.forEach(field => finalGroup[field] = group[field]);
- aggregateFunctions.forEach(func => {
- const match = /(\w+)\((\*|\w+)\)/.exec(func);
- if (match) {
- const [, aggregateFunc, aggregateField] = match;
- switch (aggregateFunc.toUpperCase()) {
- case 'SUM':
- finalGroup[func] = group.sums[aggregateField];
- break;
- case 'MIN':
- finalGroup[func] = group.mins[aggregateField];
- break;
- case 'MAX':
- finalGroup[func] = group.maxes[aggregateField];
- break;
- case 'COUNT':
- finalGroup[func] = group.count;
- break;
- // Additional aggregate functions can be handled here
- }
- }
- });
- return finalGroup;
- });
-}
-
-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 the joins
- if (joinTable && joinCondition) {
- const joinData = await readCSV(`${joinTable}.csv`);
- switch (joinType.toUpperCase()) {
- case 'INNER':
- data = performInnerJoin(data, joinData, joinCondition, fields, table);
- break;
- case 'LEFT':
- data = performLeftJoin(data, joinData, joinCondition, fields, table);
- break;
- case 'RIGHT':
- data = performRightJoin(data, joinData, joinCondition, fields, table);
- break;
- default:
- throw new Error(`Unsupported join type`);
- // Handle default case or unsupported JOIN types
- }
- }
-
- let filteredData = whereClauses.length > 0
- ? data.filter(row => whereClauses.every(clause => evaluateCondition(row, clause)))
- : data;
-
- let groupData = filteredData;
- if(hasAggregateWithoutGroupBy){
- // handling queries where there are no Group by and we are doing Aggregrate
- const output = {};
-
- fields.forEach(field => {
- const match = /(\w+)\((\*|\w+)\)/.exec(field);
- if (match) {
- const [, aggregrateFunc, aggregrateField] = match;
- switch (aggregrateFunc.toUpperCase()) {
- case 'COUNT':
- output[field] = filteredData.length;
- break;
- case 'SUM':
- output[field] = filteredData.reduce((acc, row) => acc + parseFloat(row[aggregrateField]), 0);
- break;
- case 'AVG':
- output[field] = filteredData.reduce((acc, row) => acc + parseFloat(row[aggregrateField]), 0) / filteredData.length;
- break;
- case 'MIN':
- output[field] = Math.min(...filteredData.map(row => parseFloat(row[aggregrateField])));
- break;
- case 'MAX':
- output[field] = Math.max(...filteredData.map(row => parseFloat(row[aggregrateField])));
- break;
- // Additional aggregate functions can be handled here
- }
- }
- });
-
- return [output];
- }else if(groupByFields){
- groupData = applyGroupBy(filteredData,groupByFields,fields)
-
- let orderOutput = groupData;
- if(orderByFields){
- orderOutput=groupData.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;
- });
- }
- if (limit !== null) {
- orderOutput = orderOutput.slice(0, limit);
- }
- if (isDistinct) {
- groupData = [...new Map(groupData.map(item => [fields.map(field => item[field]).join('|'), item])).values()];
- }
- return groupData;
-
-
- } else{
-
- // Order them by the specified fields
- let orderOutput = groupData;
- if (orderByFields) {
- orderOutput = groupData.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;
- });
- }
- if (limit !== null) {
- orderOutput = orderOutput.slice(0, limit);
- }
- if (isDistinct) {
- orderOutput = [...new Map(orderOutput.map(item => [fields.map(field => item[field]).join('|'), item])).values()];
- }
- return orderOutput.map(row => {
- const selectedRow = {};
- fields.forEach(field => {
- selectedRow[field]=row[field];
- });
-
- return selectedRow;
- });
- }
-}
-catch(error){
- throw new Error(`Error executing query: ${error.message}`);
-}
-}
-
-function evaluateCondition(row, clause) {
- let { field, operator, value } = clause;
-
- if (row[field] === undefined) {
- throw new Error(`Invalid field`);
- }
- // Parse row value and condition value based on their actual types
- const rowValue = parsingValue(row[field]);
- let conditionValue = parsingValue(value);
- if (operator === 'LIKE') {
- // Transform SQL LIKE pattern to JavaScript RegExp pattern
- const regexPattern = '^' + value.replace(/%/g, '.*').replace(/_/g, '.') + '$';
- const regex = new RegExp(regexPattern, 'i'); // 'i' for case-insensitive matching
- return regex.test(row[field]);
- }
- // Compare the field value with the condition value
- switch (operator) {
- case '=': return rowValue === conditionValue;
- case '!=': return rowValue !== conditionValue;
- case '>': return rowValue > conditionValue;
- case '<': return rowValue < conditionValue;
- case '>=': return rowValue >= conditionValue;
- case '<=': return rowValue <= conditionValue;
- default: throw new Error(`Unsupported operator: ${operator}`);
- }
-}
-
-function parsingValue(value) {
- // Return null or undefined as is
- if (value === null || value === undefined) {
- return value;
- }
- // If the value is a string enclosed in single or double quotes, remove them
- if (typeof value === 'string' && ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"')))) {
- value = value.substring(1, value.length - 1);
- }
- // Check if value is a number
- if (!isNaN(value) && value.trim() !== '') {
- return Number(value);
- }
- // Assume value is a string if not a number
- return value;
-}
-
-async function executeINSERTQuery(query) {
- const { table, columns, values } = parseINSERTQuery(query);
- const data = await readCSV(`${table}.csv`);
-
- // Creating a fresh row
- const FRow = {};
- columns.forEach((column, index) => {
- let value = values[index];
- if (value.startsWith("'") && value.endsWith("'")) {
- value = value.substring(1, value.length - 1);
- }
- FRow[column] = value;
- });
-
- data.push(FRow);
-
- await writeCSV(`${table}.csv`, data);
- return { message: "Row inserted successfully." };
-}
-
-
-// src/queryExecutor.js
-
-async function executeDELETEQuery(query) {
- const { table, whereClauses } = parseDeleteQuery(query);
- let data = await readCSV(`${table}.csv`);
-
- if (whereClauses.length > 0) {
- // Filter out the rows that meet the where clause conditions
- // Implement this.
- } else {
- // If no where clause, clear the entire table
- data = [];
- }
-
- // Save the updated data back to the CSV file
- await writeCSV(`${table}.csv`, data);
-
- return { message: "Rows deleted successfully." };
-}
-module.exports = { executeSELECTQuery, executeINSERTQuery, executeDELETEQuery };
\ No newline at end of file
+module.exports = {readCSV, writeCSV ,parseDeleteQuery, parseSelectQuery, parseINSERTQuery, executeSELECTQuery, executeINSERTQuery, executeDELETEQuery };
\ No newline at end of file
diff --git a/src/queryExecutor.js b/src/queryExecutor.js
index ca1b2b107..8b8205a92 100644
--- a/src/queryExecutor.js
+++ b/src/queryExecutor.js
@@ -1,3 +1,331 @@
+// src/index.js
+
+
+const {parseSelectQuery, parseINSERTQuery, parseDeleteQuery} = require('./queryParser');
+const { readCSV, writeCSV } = require('./csvReader');
+
+// Helper functions for different JOIN types
+function performInnerJoin(data, joinData, joinCondition, fields, table) {
+ return data.flatMap(mainRow => {
+ const matchedJoinRows = joinData.filter(joinRow => {
+ const mainValue = mainRow[joinCondition.left.split('.')[1]];
+ const joinValue = joinRow[joinCondition.right.split('.')[1]];
+ return mainValue === joinValue;
+ });
+
+ // If there are matching rows, create a row for each match
+ return matchedJoinRows.map(joinRow => {
+ return fields.reduce((acc, field) => {
+ const [tableName, fieldName] = field.split('.');
+ acc[field] = tableName === table ? mainRow[fieldName] : joinRow[fieldName];
+ return acc;
+ }, {});
+ });
+ });
+}
+
+function performLeftJoin(data, joinData, joinCondition, fields, table) {
+ const leftJoinedData = data.flatMap(mainRow => {
+ const matchedJoinRows = joinData.filter(joinRow => {
+ const mainValue = mainRow[joinCondition.left.split('.')[1]];
+ const joinValue = joinRow[joinCondition.right.split('.')[1]];
+ return mainValue === joinValue;
+ });
+
+ if (matchedJoinRows.length === 0) {
+ return [createResultRow(mainRow, null, fields, table, true)];
+ }
+ return matchedJoinRows.map(joinRow => createResultRow(mainRow, joinRow, fields, table, true));
+
+ });
+ return leftJoinedData;
+}
+
+function createResultRow(mainRow, joinRow, fields, table, includeAllMainFields) {
+ const resultRow = {};
+ if (includeAllMainFields) {
+ // Include all fields from the main table
+ Object.keys(mainRow || {}).forEach(key => {
+ const prefixedKey = `${table}.${key}`;
+ resultRow[prefixedKey] = mainRow ? mainRow[key] : null;
+ });
+ }
+ // Now, add or overwrite with the fields specified in the query
+ fields.forEach(field => {
+ const [tableName, fieldName] = field.includes('.') ? field.split('.') : [table, field];
+ resultRow[field] = tableName === table && mainRow ? mainRow[fieldName] : joinRow ? joinRow[fieldName] : null;
+ });
+ return resultRow;
+}
+
+function performRightJoin(data, joinData, joinCondition, fields, table) {
+ // Cache the structure of a main table row (keys only)
+
+ const RowStructure = data.length > 0 ? Object.keys(data[0]).reduce((acc, key) => {
+ acc[key] = null; // Set all values to null initially
+ return acc;
+ }, {}) : {};
+ let rightJoinedData = joinData.map(joinRow => {
+ const mainRowMatch = data.find(mainRow => {
+ const mainValue = getValueFromGivenRow(mainRow, joinCondition.left);
+ const joinValue = getValueFromGivenRow(joinRow, joinCondition.right);
+ return mainValue === joinValue;
+ });
+ // Use the cached structure if no match is found
+ const mainRowToUse = mainRowMatch || RowStructure;
+ // Include all necessary fields from the 'student' table
+ return createResultRow(mainRowToUse, joinRow, fields, table, true);
+ });
+ return rightJoinedData
+}
+
+function getValueFromGivenRow(row, compoundFieldName) {
+ const [tableName, fieldName] = compoundFieldName.split('.');
+ return row[`${tableName}.${fieldName}`] || row[fieldName];
+}
+
+function applyGroupBy(data, groupByFields, aggregateFunctions) {
+ const groupResult = {};
+ data.forEach(row => {
+ // Generate a key for the group
+ const Key = groupByFields.map(field => row[field]).join('-');
+ // Initialize group in results if it doesn't exist
+ if (!groupResult[Key]) {
+ groupResult[Key] = { count: 0, sums: {}, mins: {}, maxes: {} };
+ groupByFields.forEach(field => groupResult[Key][field] = row[field]);
+ }
+ // Aggregate calculations
+ groupResult[Key].count += 1;
+ aggregateFunctions.forEach(func => {
+ const match = /(\w+)\((\w+)\)/.exec(func);
+ if (match) {
+ const [, aggregateFunc, aggregateField] = match;
+ const value = parseFloat(row[aggregateField]);
+ switch (aggregateFunc.toUpperCase()) {
+ case 'SUM':
+ groupResult[Key].sums[aggregateField] = (groupResult[Key].sums[aggregateField] || 0) + value;
+ break;
+ case 'MIN':
+ groupResult[Key].mins[aggregateField] = Math.min(groupResult[Key].mins[aggregateField] || value, value);
+ break;
+ case 'MAX':
+ groupResult[Key].maxes[aggregateField] = Math.max(groupResult[Key].maxes[aggregateField] || value, value);
+ break;
+ // Additional aggregate functions can be added here
+ }
+ }
+ });
+ });
+ // Convert grouped results into an array format
+ return Object.values(groupResult).map(group => {
+ // Construct the final grouped object based on required fields
+ const finalGroup = {};
+ groupByFields.forEach(field => finalGroup[field] = group[field]);
+ aggregateFunctions.forEach(func => {
+ const match = /(\w+)\((\*|\w+)\)/.exec(func);
+ if (match) {
+ const [, aggregateFunc, aggregateField] = match;
+ switch (aggregateFunc.toUpperCase()) {
+ case 'SUM':
+ finalGroup[func] = group.sums[aggregateField];
+ break;
+ case 'MIN':
+ finalGroup[func] = group.mins[aggregateField];
+ break;
+ case 'MAX':
+ finalGroup[func] = group.maxes[aggregateField];
+ break;
+ case 'COUNT':
+ finalGroup[func] = group.count;
+ break;
+ // Additional aggregate functions can be handled here
+ }
+ }
+ });
+ return finalGroup;
+ });
+}
+
+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 the joins
+ if (joinTable && joinCondition) {
+ const joinData = await readCSV(`${joinTable}.csv`);
+ switch (joinType.toUpperCase()) {
+ case 'INNER':
+ data = performInnerJoin(data, joinData, joinCondition, fields, table);
+ break;
+ case 'LEFT':
+ data = performLeftJoin(data, joinData, joinCondition, fields, table);
+ break;
+ case 'RIGHT':
+ data = performRightJoin(data, joinData, joinCondition, fields, table);
+ break;
+ default:
+ throw new Error(`Unsupported join type`);
+ // Handle default case or unsupported JOIN types
+ }
+ }
+
+ let filteredData = whereClauses.length > 0
+ ? data.filter(row => whereClauses.every(clause => evaluateCondition(row, clause)))
+ : data;
+
+ let groupData = filteredData;
+ if(hasAggregateWithoutGroupBy){
+ // handling queries where there are no Group by and we are doing Aggregrate
+ const output = {};
+
+ fields.forEach(field => {
+ const match = /(\w+)\((\*|\w+)\)/.exec(field);
+ if (match) {
+ const [, aggregrateFunc, aggregrateField] = match;
+ switch (aggregrateFunc.toUpperCase()) {
+ case 'COUNT':
+ output[field] = filteredData.length;
+ break;
+ case 'SUM':
+ output[field] = filteredData.reduce((acc, row) => acc + parseFloat(row[aggregrateField]), 0);
+ break;
+ case 'AVG':
+ output[field] = filteredData.reduce((acc, row) => acc + parseFloat(row[aggregrateField]), 0) / filteredData.length;
+ break;
+ case 'MIN':
+ output[field] = Math.min(...filteredData.map(row => parseFloat(row[aggregrateField])));
+ break;
+ case 'MAX':
+ output[field] = Math.max(...filteredData.map(row => parseFloat(row[aggregrateField])));
+ break;
+ // Additional aggregate functions can be handled here
+ }
+ }
+ });
+
+ return [output];
+ }else if(groupByFields){
+ groupData = applyGroupBy(filteredData,groupByFields,fields)
+
+ let orderOutput = groupData;
+ if(orderByFields){
+ orderOutput=groupData.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;
+ });
+ }
+ if (limit !== null) {
+ orderOutput = orderOutput.slice(0, limit);
+ }
+ if (isDistinct) {
+ groupData = [...new Map(groupData.map(item => [fields.map(field => item[field]).join('|'), item])).values()];
+ }
+ return groupData;
+
+
+ } else{
+
+ // Order them by the specified fields
+ let orderOutput = groupData;
+ if (orderByFields) {
+ orderOutput = groupData.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;
+ });
+ }
+ if (limit !== null) {
+ orderOutput = orderOutput.slice(0, limit);
+ }
+ if (isDistinct) {
+ orderOutput = [...new Map(orderOutput.map(item => [fields.map(field => item[field]).join('|'), item])).values()];
+ }
+ return orderOutput.map(row => {
+ const selectedRow = {};
+ fields.forEach(field => {
+ selectedRow[field]=row[field];
+ });
+
+ return selectedRow;
+ });
+ }
+}
+catch(error){
+ throw new Error(`Error executing query: ${error.message}`);
+}
+}
+
+function evaluateCondition(row, clause) {
+ let { field, operator, value } = clause;
+
+ if (row[field] === undefined) {
+ throw new Error(`Invalid field`);
+ }
+ // Parse row value and condition value based on their actual types
+ const rowValue = parsingValue(row[field]);
+ let conditionValue = parsingValue(value);
+ if (operator === 'LIKE') {
+ // Transform SQL LIKE pattern to JavaScript RegExp pattern
+ const regexPattern = '^' + value.replace(/%/g, '.*').replace(/_/g, '.') + '$';
+ const regex = new RegExp(regexPattern, 'i'); // 'i' for case-insensitive matching
+ return regex.test(row[field]);
+ }
+ // Compare the field value with the condition value
+ switch (operator) {
+ case '=': return rowValue === conditionValue;
+ case '!=': return rowValue !== conditionValue;
+ case '>': return rowValue > conditionValue;
+ case '<': return rowValue < conditionValue;
+ case '>=': return rowValue >= conditionValue;
+ case '<=': return rowValue <= conditionValue;
+ default: throw new Error(`Unsupported operator: ${operator}`);
+ }
+}
+
+function parsingValue(value) {
+ // Return null or undefined as is
+ if (value === null || value === undefined) {
+ return value;
+ }
+ // If the value is a string enclosed in single or double quotes, remove them
+ if (typeof value === 'string' && ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"')))) {
+ value = value.substring(1, value.length - 1);
+ }
+ // Check if value is a number
+ if (!isNaN(value) && value.trim() !== '') {
+ return Number(value);
+ }
+ // Assume value is a string if not a number
+ return value;
+}
+
+async function executeINSERTQuery(query) {
+ const { table, columns, values } = parseINSERTQuery(query);
+ const data = await readCSV(`${table}.csv`);
+
+ // Creating a fresh row
+ const FRow = {};
+ columns.forEach((column, index) => {
+ let value = values[index];
+ if (value.startsWith("'") && value.endsWith("'")) {
+ value = value.substring(1, value.length - 1);
+ }
+ FRow[column] = value;
+ });
+
+ data.push(FRow);
+
+ await writeCSV(`${table}.csv`, data);
+ return { message: "Row inserted successfully." };
+}
+
+
// src/queryExecutor.js
async function executeDELETEQuery(query) {
diff --git a/tests/step-19/deleteExecutor.test.js b/tests/step-19/deleteExecutor.test.js
deleted file mode 100644
index 11ae617b7..000000000
--- a/tests/step-19/deleteExecutor.test.js
+++ /dev/null
@@ -1,31 +0,0 @@
-const { executeDELETEQuery } = require('../../src/index');
-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');
-});
\ No newline at end of file
diff --git a/tests/step-19/insertExecuter.test.js b/tests/step-19/insertExecuter.test.js
deleted file mode 100644
index 8c405f727..000000000
--- a/tests/step-19/insertExecuter.test.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const { executeINSERTQuery } = require('../../src/index');
-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');
- console.log(updatedData)
- expect(newEntry).toBeDefined();
- expect(newEntry.grade).toEqual('A');
-
- // Cleanup: Delete grades.csv
- fs.unlinkSync('grades.csv');
-});
\ No newline at end of file
diff --git a/tests/step-20/cli.js b/tests/step-20/cli.js
deleted file mode 100644
index fbba6c02c..000000000
--- a/tests/step-20/cli.js
+++ /dev/null
@@ -1,53 +0,0 @@
-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]) {
- console.log(match[1]);
- console.log(typeof match[1])
- // Parse the captured JSON string
- // const results = JSON.parse(match[1]);
-
- // Validation logic
- expect(JSON.parse(match[1])).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\" } ]")
- ([
- { 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' },
- ]);
- console.log("Test passed successfully");
- } else {
- done()
- 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
-});
\ No newline at end of file
diff --git a/tests/step-20/deleteExecutor.test.js b/tests/step-20/deleteExecutor.test.js
deleted file mode 100644
index 636403858..000000000
--- a/tests/step-20/deleteExecutor.test.js
+++ /dev/null
@@ -1,31 +0,0 @@
-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');
-});
\ No newline at end of file
diff --git a/tests/step-20/insertExecuter.test.js b/tests/step-20/insertExecuter.test.js
deleted file mode 100644
index 581d17f73..000000000
--- a/tests/step-20/insertExecuter.test.js
+++ /dev/null
@@ -1,33 +0,0 @@
-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');
- console.log(updatedData)
- expect(newEntry).toBeDefined();
- expect(newEntry.grade).toEqual('A');
-
- // Cleanup: Delete grades.csv
- fs.unlinkSync('grades.csv');
-});
\ No newline at end of file