Skip to content

Commit cf4c4a9

Browse files
committed
feat: handle Subscripts (slice in queries)
1 parent 66fb11a commit cf4c4a9

File tree

4 files changed

+42
-3
lines changed

4 files changed

+42
-3
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/django-check/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "django-check"
3-
version = "0.1.2"
3+
version = "0.1.3"
44
rust-version = { workspace = true }
55
license = { workspace = true }
66
authors = { workspace = true }

crates/django-check/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "maturin"
44

55
[project]
66
name = "djch"
7-
version = "0.1.2"
7+
version = "0.1.3"
88
description = "Static N+1 query detector for Django ORM – fast Rust-powered checker"
99
# For PyPI long description (shows formatted on project page)
1010
readme = {file = "README.md", content-type = "text/markdown"}

crates/django-check_semantic/src/passes/n_plus_one.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ impl<'a> QuerySetResolver<'a> {
8383
Expr::Call(call) => self.resolve_call(call),
8484
Expr::Attribute(attr) => self.resolve_attribute(attr),
8585
Expr::Name(name) => self.symbols.lookup(&name.id).cloned(),
86+
// Handle slice like myqueryset[0:100]
87+
Expr::Subscript(subscript) => self.resolve(&subscript.value),
8688
_ => None,
8789
}
8890
}
@@ -1510,4 +1512,41 @@ for t in tier1s:
15101512
let diags = run_pass(source);
15111513
assert_eq!(diags.len(), 1);
15121514
}
1515+
1516+
#[test]
1517+
fn detect_query_using_subscript() {
1518+
let source = r#"
1519+
class User(Model):
1520+
name = models.CharField()
1521+
1522+
class Payment(Model):
1523+
user = models.ForeignKey(User, related_name="payments")
1524+
amount = models.FloatField()
1525+
1526+
payments = Payment.objects.all().order_by("-amount")
1527+
top_payments = payments[0:10]
1528+
for payment in top_payments:
1529+
print(payment.user.name)
1530+
"#;
1531+
let diags = run_pass(source);
1532+
assert_eq!(diags.len(), 1);
1533+
}
1534+
1535+
#[test]
1536+
fn detect_query_using_subscript_in_for_stmt() {
1537+
let source = r#"
1538+
class User(Model):
1539+
name = models.CharField()
1540+
1541+
class Payment(Model):
1542+
user = models.ForeignKey(User, related_name="payments")
1543+
amount = models.FloatField()
1544+
1545+
payments = Payment.objects.all().order_by("-amount")
1546+
for payment in payments[0:10]:
1547+
print(payment.user.name)
1548+
"#;
1549+
let diags = run_pass(source);
1550+
assert_eq!(diags.len(), 1);
1551+
}
15131552
}

0 commit comments

Comments
 (0)