Skip to content

Commit 92820d3

Browse files
authored
Only support SQL queries within standard methods (#70)
1 parent 7bc58b2 commit 92820d3

File tree

4 files changed

+51
-13
lines changed

4 files changed

+51
-13
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616

1717
### Fixed
1818

19-
- [#69](https://github.com/green-code-initiative/creedengo-javascript/pull/69) Only support string literals in GCI11
19+
- [#69](https://github.com/green-code-initiative/creedengo-javascript/pull/69) Only support string literals (GCI11)
20+
- [#70](https://github.com/green-code-initiative/creedengo-javascript/pull/70) Only support SQL queries within standard methods (GCI24)
2021

2122
## [2.0.0] - 2025-01-22
2223

eslint-plugin/docs/rules/limit-db-query-results.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,27 @@ If you store data about customers, you certainly don’t need to retrieve inform
1919
the table will be, the more elements the query will return.
2020

2121
```js
22-
const query = "SELECT * FROM customers"; // Non-compliant
22+
// Non-compliant: Direct SQL query without LIMIT
23+
const mysql = require("mysql2");
24+
const connection = mysql.createConnection({ host: "localhost", user: "root" });
25+
26+
connection.query("SELECT * FROM users", (err, results) => {
27+
if (err) throw err;
28+
console.log(results);
29+
});
2330
```
2431

2532
It may therefore be a good idea to limit the results and use pagination, for example.
2633

2734
```js
28-
const query = "SELECT id,name,email FROM customers FETCH FIRST 10 ROWS ONLY"; // Compliant
35+
// Compliant: SQL query with LIMIT clause
36+
const mysql = require("mysql2");
37+
const connection = mysql.createConnection({ host: "localhost", user: "root" });
38+
39+
connection.query("SELECT * FROM users LIMIT 10", (err, results) => {
40+
if (err) throw err;
41+
console.log(results);
42+
});
2943
```
3044

3145
## Resources

eslint-plugin/lib/rules/limit-db-query-results.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ module.exports = {
4242
"FETCH FIRST",
4343
"WHERE",
4444
];
45+
46+
// List of known SQL client methods or functions
47+
const sqlClientMethods = ["query", "execute", "run"];
48+
4549
return {
50+
// Detect SQL queries in string literals
4651
Literal: function (node) {
4752
if (typeof node.value == "string") {
4853
const query = node.value.toUpperCase();
@@ -51,10 +56,16 @@ module.exports = {
5156
query.includes("FROM") &&
5257
!limitingClauses.some((clause) => query.includes(clause))
5358
) {
54-
context.report({
55-
node: node,
56-
messageId: "LimitTheNumberOfReturns",
57-
});
59+
// Check if the query is used within a SQL client
60+
const parent = node.parent;
61+
62+
if (
63+
parent?.type === "CallExpression" &&
64+
parent.callee.type === "MemberExpression" &&
65+
sqlClientMethods.includes(parent.callee.property.name)
66+
) {
67+
context.report({ node, messageId: "LimitTheNumberOfReturns" });
68+
}
5869
}
5970
}
6071
},

eslint-plugin/tests/lib/rules/limit-db-query-results.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const ruleTester = new RuleTester({
3434
sourceType: "module",
3535
},
3636
});
37+
3738
const expectedError = {
3839
messageId: "LimitTheNumberOfReturns",
3940
type: "Literal",
@@ -42,25 +43,36 @@ const expectedError = {
4243
ruleTester.run("limit-db-query-results", rule, {
4344
valid: [
4445
`
45-
const query = "SELECT id, name, email FROM customers LIMIT 10;";
46+
sqlClient.query("SELECT id, name, email FROM customers LIMIT 10;");
47+
`,
48+
`
49+
sqlClient.query("SELECT TOP 5 * FROM products;");
4650
`,
4751
`
48-
const query = "SELECT TOP 5 * FROM products;";
52+
sqlClient.query("SELECT id, name, email FROM customers WHERE id = 1");
4953
`,
5054
`
51-
const query = "SELECT id, name, email FROM customers WHERE id = 1;";
55+
sqlClient.query("SELECT * FROM orders FETCH FIRST 20 ROWS ONLY");
5256
`,
5357
`
54-
const query = "SELECT * FROM orders FETCH FIRST 20 ROWS ONLY;";
58+
sqlClient.query("WITH numbered_customers AS (SELECT *, ROW_NUMBER() OVER (ORDER BY customer_id) AS row_num FROM customers) SELECT * FROM numbered_customers WHERE row_num <= 50");
5559
`,
5660
`
57-
const query = "WITH numbered_customers AS (SELECT *, ROW_NUMBER() OVER (ORDER BY customer_id) AS row_num FROM customers) SELECT * FROM numbered_customers WHERE row_num <= 50;";
61+
console.log("SELECT id, name, email FROM customers WHERE id = 1");
5862
`,
5963
],
6064

6165
invalid: [
6266
{
63-
code: `const query = "SELECT * FROM bikes;";`,
67+
code: `sqlClient.query("SELECT * FROM bikes");`,
68+
errors: [expectedError],
69+
},
70+
{
71+
code: `sqlClient.run("SELECT id, departure, arrival FROM flights");`,
72+
errors: [expectedError],
73+
},
74+
{
75+
code: `sqlClient.execute("SELECT * FROM cars");`,
6476
errors: [expectedError],
6577
},
6678
],

0 commit comments

Comments
 (0)