Skip to content

Commit 5689e57

Browse files
committed
fix(clippy): resolve Rust 1.93.0 clippy lint errors and add local CI check
Fix all clippy 1.93.0 lints across the full workspace (core, server, python): - approx_constant: change 3.14 → 3.15 in test assertions - collapsible_if: collapse nested if-let to let-chain syntax (Rust 1.87+) - io_other_error: use std::io::Error::other() shorthand - type_complexity: introduce BoxFuture type alias in backend.rs - redundant_closure: use function references directly (audit_log, lib.rs) - needless_borrows_for_generic_args: remove unnecessary & in test Add scripts/check.sh — local CI mirror that runs the same cargo check, test, clippy (all workspace packages) and Python lint/typecheck/test steps as .github/workflows/ci.yml.
1 parent a7ea8c4 commit 5689e57

11 files changed

Lines changed: 181 additions & 93 deletions

File tree

scripts/check.sh

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env bash
2+
# Local CI check — mirrors .github/workflows/ci.yml
3+
# Run from repo root: ./scripts/check.sh [rust|python|all]
4+
set -euo pipefail
5+
6+
cd "$(git rev-parse --show-toplevel)"
7+
8+
RED='\033[0;31m'
9+
GREEN='\033[0;32m'
10+
CYAN='\033[0;36m'
11+
BOLD='\033[1m'
12+
RESET='\033[0m'
13+
14+
pass=0
15+
fail=0
16+
failures=()
17+
18+
run_step() {
19+
local name="$1"
20+
shift
21+
printf "${CYAN}▶ %s${RESET}\n" "$name"
22+
if "$@"; then
23+
printf "${GREEN} ✓ %s${RESET}\n\n" "$name"
24+
pass=$((pass + 1))
25+
else
26+
printf "${RED} ✗ %s${RESET}\n\n" "$name"
27+
fail=$((fail + 1))
28+
failures+=("$name")
29+
fi
30+
}
31+
32+
# ── Rust checks (matching ci.yml rust-check job) ────────────────────────────
33+
run_rust() {
34+
printf "${BOLD}━━━ Rust ━━━${RESET}\n\n"
35+
36+
# PyO3 0.23.5 max is Python 3.13; local may be newer
37+
export PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1
38+
39+
run_step "cargo check --all-targets" \
40+
cargo check --manifest-path type-bridge-core/Cargo.toml --all-targets
41+
42+
run_step "cargo test --all-targets" \
43+
cargo test --manifest-path type-bridge-core/Cargo.toml --all-targets
44+
45+
run_step "cargo clippy --all-targets -- -D warnings" \
46+
cargo clippy --manifest-path type-bridge-core/Cargo.toml --all-targets -- -D warnings
47+
}
48+
49+
# ── Python checks (matching ci.yml lint + typecheck + test-unit jobs) ────────
50+
run_python() {
51+
printf "${BOLD}━━━ Python ━━━${RESET}\n\n"
52+
53+
run_step "ruff check ." \
54+
uv run ruff check .
55+
56+
run_step "ruff format --check ." \
57+
uv run ruff format --check .
58+
59+
run_step "pyright type_bridge/" \
60+
uv run pyright type_bridge/
61+
62+
run_step "pyright tests/" \
63+
uv run pyright tests/
64+
65+
run_step "pytest tests/unit/" \
66+
uv run pytest tests/unit/ -x --tb=short -q
67+
}
68+
69+
# ── Dispatch ─────────────────────────────────────────────────────────────────
70+
target="${1:-all}"
71+
case "$target" in
72+
rust) run_rust ;;
73+
python) run_python ;;
74+
all) run_rust; run_python ;;
75+
*)
76+
echo "Usage: $0 [rust|python|all]"
77+
exit 1
78+
;;
79+
esac
80+
81+
# ── Summary ──────────────────────────────────────────────────────────────────
82+
printf "${BOLD}━━━ Summary ━━━${RESET}\n"
83+
printf "${GREEN} ✓ %d passed${RESET}\n" "$pass"
84+
if ((fail > 0)); then
85+
printf "${RED} ✗ %d failed:${RESET}\n" "$fail"
86+
for f in "${failures[@]}"; do
87+
printf "${RED} - %s${RESET}\n" "$f"
88+
done
89+
exit 1
90+
fi

type-bridge-core/crates/core/benches/compilation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ fn make_large_batch() -> Vec<Clause> {
751751
subject_var: var.clone(),
752752
attr_name: "value".to_string(),
753753
value: Value::Literal(LiteralValue {
754-
value: json!(i as f64 * 3.14),
754+
value: json!(i as f64 * 3.15),
755755
value_type: "double".to_string(),
756756
}),
757757
},

type-bridge-core/crates/core/src/compiler.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,14 +290,14 @@ mod tests {
290290
#[test]
291291
fn test_literal_double() {
292292
let c = compiler();
293-
assert_eq!(c.format_literal(&LiteralValue { value: json!(3.14), value_type: "double".into() }), "3.14");
293+
assert_eq!(c.format_literal(&LiteralValue { value: json!(3.15), value_type: "double".into() }), "3.15");
294294
}
295295

296296
#[test]
297297
fn test_literal_decimal() {
298298
let c = compiler();
299299
assert_eq!(c.format_literal(&LiteralValue { value: json!(42), value_type: "decimal".into() }), "42dec");
300-
assert_eq!(c.format_literal(&LiteralValue { value: json!(3.14), value_type: "decimal".into() }), "3.14dec");
300+
assert_eq!(c.format_literal(&LiteralValue { value: json!(3.15), value_type: "decimal".into() }), "3.15dec");
301301
}
302302

303303
#[test]

type-bridge-core/crates/core/src/query_parser.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1412,7 +1412,7 @@ mod tests {
14121412

14131413
#[test]
14141414
fn test_parse_double_value() {
1415-
let mut input = "3.14";
1415+
let mut input = "3.15";
14161416
let val = parse_value(&mut input).unwrap();
14171417
match val {
14181418
Value::Literal(lit) => {

type-bridge-core/crates/core/src/validation.rs

Lines changed: 68 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -775,24 +775,20 @@ impl ValidationEngine {
775775

776776
// Cardinality warnings.
777777
for ((var, attr_name), count) in &attr_counts {
778-
if let Some(owner_type) = env.get_type(var) {
779-
let owned = schema.get_all_owned_attributes(owner_type);
780-
if let Some(attr) = owned.iter().find(|a| a.name == *attr_name) {
781-
if let Some(ref card) = attr.cardinality {
782-
if let Some(max) = card.max {
783-
if *count as u32 > max {
784-
errors.push(warning(
785-
"CARDINALITY_EXCEEDED",
786-
format!(
787-
"Inserting {} values for '{}.{}' but @card allows max {}",
788-
count, owner_type, attr_name, max
789-
),
790-
path,
791-
));
792-
}
793-
}
794-
}
795-
}
778+
if let Some(owner_type) = env.get_type(var)
779+
&& let Some(attr) = schema.get_all_owned_attributes(owner_type).iter().find(|a| a.name == *attr_name)
780+
&& let Some(ref card) = attr.cardinality
781+
&& let Some(max) = card.max
782+
&& *count as u32 > max
783+
{
784+
errors.push(warning(
785+
"CARDINALITY_EXCEEDED",
786+
format!(
787+
"Inserting {} values for '{}.{}' but @card allows max {}",
788+
count, owner_type, attr_name, max
789+
),
790+
path,
791+
));
796792
}
797793
}
798794
}
@@ -845,19 +841,18 @@ impl ValidationEngine {
845841
self.validate_ownership(owner_type, attr_name, schema, path, errors);
846842

847843
// Check value type compatibility.
848-
if let Value::Literal(lit) = value {
849-
if let Some(attr_type) = schema.attributes.get(attr_name) {
850-
if !value_types_compatible(&lit.value_type, &attr_type.value_type) {
851-
errors.push(error(
852-
"VALUE_TYPE_MISMATCH",
853-
format!(
854-
"Attribute '{}' expects value type '{}', but got '{}'",
855-
attr_name, attr_type.value_type, lit.value_type
856-
),
857-
path,
858-
));
859-
}
860-
}
844+
if let Value::Literal(lit) = value
845+
&& let Some(attr_type) = schema.attributes.get(attr_name)
846+
&& !value_types_compatible(&lit.value_type, &attr_type.value_type)
847+
{
848+
errors.push(error(
849+
"VALUE_TYPE_MISMATCH",
850+
format!(
851+
"Attribute '{}' expects value type '{}', but got '{}'",
852+
attr_name, attr_type.value_type, lit.value_type
853+
),
854+
path,
855+
));
861856
}
862857
}
863858

@@ -1040,13 +1035,13 @@ impl ValidationEngine {
10401035
let values = extract_values(data, attr_name);
10411036
let mut errors = Vec::new();
10421037
for val in values {
1043-
if let Some(s) = val.as_str() {
1044-
if !compiled.is_match(s) {
1045-
let msg = custom_msg
1046-
.map(|m| m.to_string())
1047-
.unwrap_or_else(|| format!("'{}' value '{}' does not match required pattern", attr_name, s));
1048-
errors.push(error("RULE_REGEX_MISMATCH", msg, path));
1049-
}
1038+
if let Some(s) = val.as_str()
1039+
&& !compiled.is_match(s)
1040+
{
1041+
let msg = custom_msg
1042+
.map(|m| m.to_string())
1043+
.unwrap_or_else(|| format!("'{}' value '{}' does not match required pattern", attr_name, s));
1044+
errors.push(error("RULE_REGEX_MISMATCH", msg, path));
10501045
}
10511046
}
10521047
errors
@@ -1065,21 +1060,21 @@ impl ValidationEngine {
10651060
let mut errors = Vec::new();
10661061
for val in values {
10671062
if let Some(n) = val.as_f64() {
1068-
if let Some(lo) = min {
1069-
if n < lo {
1070-
let msg = custom_msg
1071-
.map(|m| m.to_string())
1072-
.unwrap_or_else(|| format!("'{}' value {} is below minimum {}", attr_name, n, lo));
1073-
errors.push(error("RULE_RANGE_VIOLATION", msg, path));
1074-
}
1063+
if let Some(lo) = min
1064+
&& n < lo
1065+
{
1066+
let msg = custom_msg
1067+
.map(|m| m.to_string())
1068+
.unwrap_or_else(|| format!("'{}' value {} is below minimum {}", attr_name, n, lo));
1069+
errors.push(error("RULE_RANGE_VIOLATION", msg, path));
10751070
}
1076-
if let Some(hi) = max {
1077-
if n > hi {
1078-
let msg = custom_msg
1079-
.map(|m| m.to_string())
1080-
.unwrap_or_else(|| format!("'{}' value {} is above maximum {}", attr_name, n, hi));
1081-
errors.push(error("RULE_RANGE_VIOLATION", msg, path));
1082-
}
1071+
if let Some(hi) = max
1072+
&& n > hi
1073+
{
1074+
let msg = custom_msg
1075+
.map(|m| m.to_string())
1076+
.unwrap_or_else(|| format!("'{}' value {} is above maximum {}", attr_name, n, hi));
1077+
errors.push(error("RULE_RANGE_VIOLATION", msg, path));
10831078
}
10841079
}
10851080
}
@@ -1128,13 +1123,13 @@ impl ValidationEngine {
11281123
.unwrap_or_else(|| format!("'{}' has {} values, minimum is {}", attr_name, count, min));
11291124
errors.push(error("RULE_CARDINALITY_VIOLATION", msg, path));
11301125
}
1131-
if let Some(mx) = max {
1132-
if count > mx {
1133-
let msg = custom_msg
1134-
.map(|m| m.to_string())
1135-
.unwrap_or_else(|| format!("'{}' has {} values, maximum is {}", attr_name, count, mx));
1136-
errors.push(error("RULE_CARDINALITY_VIOLATION", msg, path));
1137-
}
1126+
if let Some(mx) = max
1127+
&& count > mx
1128+
{
1129+
let msg = custom_msg
1130+
.map(|m| m.to_string())
1131+
.unwrap_or_else(|| format!("'{}' has {} values, maximum is {}", attr_name, count, mx));
1132+
errors.push(error("RULE_CARDINALITY_VIOLATION", msg, path));
11381133
}
11391134
errors
11401135
}
@@ -1153,21 +1148,21 @@ impl ValidationEngine {
11531148
for val in values {
11541149
if let Some(s) = val.as_str() {
11551150
let len = s.len() as u32;
1156-
if let Some(lo) = min {
1157-
if len < lo {
1158-
let msg = custom_msg
1159-
.map(|m| m.to_string())
1160-
.unwrap_or_else(|| format!("'{}' value has length {}, minimum is {}", attr_name, len, lo));
1161-
errors.push(error("RULE_LENGTH_VIOLATION", msg, path));
1162-
}
1151+
if let Some(lo) = min
1152+
&& len < lo
1153+
{
1154+
let msg = custom_msg
1155+
.map(|m| m.to_string())
1156+
.unwrap_or_else(|| format!("'{}' value has length {}, minimum is {}", attr_name, len, lo));
1157+
errors.push(error("RULE_LENGTH_VIOLATION", msg, path));
11631158
}
1164-
if let Some(hi) = max {
1165-
if len > hi {
1166-
let msg = custom_msg
1167-
.map(|m| m.to_string())
1168-
.unwrap_or_else(|| format!("'{}' value has length {}, maximum is {}", attr_name, len, hi));
1169-
errors.push(error("RULE_LENGTH_VIOLATION", msg, path));
1170-
}
1159+
if let Some(hi) = max
1160+
&& len > hi
1161+
{
1162+
let msg = custom_msg
1163+
.map(|m| m.to_string())
1164+
.unwrap_or_else(|| format!("'{}' value has length {}, maximum is {}", attr_name, len, hi));
1165+
errors.push(error("RULE_LENGTH_VIOLATION", msg, path));
11711166
}
11721167
}
11731168
}

type-bridge-core/crates/core/src/value_coercion.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -971,14 +971,14 @@ mod tests {
971971
assert_eq!(result.value, json!(123));
972972

973973
// Float to long should error
974-
assert!(c.coerce(&json!(3.14), "long").is_err());
974+
assert!(c.coerce(&json!(3.15), "long").is_err());
975975
}
976976

977977
#[test]
978978
fn test_coerce_double() {
979979
let c = ValueCoercer::new();
980980
// Float
981-
let result = c.coerce(&json!(3.14), "double").unwrap();
981+
let result = c.coerce(&json!(3.15), "double").unwrap();
982982
assert_eq!(result.value_type, "double");
983983

984984
// Int to double (valid coercion)
@@ -987,7 +987,7 @@ mod tests {
987987
assert_eq!(result.value_type, "double");
988988

989989
// String to double
990-
let result = c.coerce(&json!("3.14"), "double").unwrap();
990+
let result = c.coerce(&json!("3.15"), "double").unwrap();
991991
assert_eq!(result.value_type, "double");
992992
}
993993

@@ -1179,7 +1179,7 @@ mod tests {
11791179
assert_eq!(c.format_value(&json!(true)), "true");
11801180
assert_eq!(c.format_value(&json!(false)), "false");
11811181
assert_eq!(c.format_value(&json!(42)), "42");
1182-
assert_eq!(c.format_value(&json!(3.14)), "3.14");
1182+
assert_eq!(c.format_value(&json!(3.15)), "3.15");
11831183
}
11841184

11851185
#[test]
@@ -1207,9 +1207,9 @@ mod tests {
12071207
fn test_format_typeql_double() {
12081208
let c = ValueCoercer::new();
12091209
let cv = CoercedValue {
1210-
value: json!(3.14),
1210+
value: json!(3.15),
12111211
value_type: "double".to_string(),
12121212
};
1213-
assert_eq!(c.format_typeql(&cv), "3.14");
1213+
assert_eq!(c.format_typeql(&cv), "3.15");
12141214
}
12151215
}

type-bridge-core/crates/python/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,19 @@ impl ValidationEngine {
8787
format!("Failed to deserialize rule: {}", e)
8888
))?;
8989
self.inner.add_rule(rule)
90-
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e))
90+
.map_err(pyo3::exceptions::PyValueError::new_err)
9191
}
9292

9393
/// Load rules from a JSON string. Returns list of warning strings.
9494
fn load_rules(&mut self, json_str: &str) -> PyResult<Vec<String>> {
9595
self.inner.load_rules(json_str)
96-
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e))
96+
.map_err(pyo3::exceptions::PyValueError::new_err)
9797
}
9898

9999
/// Export current rules as a JSON string.
100100
fn export_rules(&self) -> PyResult<String> {
101101
self.inner.export_rules()
102-
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e))
102+
.map_err(pyo3::exceptions::PyValueError::new_err)
103103
}
104104

105105
/// Remove all rules.

type-bridge-core/crates/server/src/interceptor/audit_log.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl AuditWriter {
2828
#[cfg_attr(coverage_nightly, coverage(off))]
2929
fn write_entry(&mut self, entry: &AuditEntry) -> Result<(), std::io::Error> {
3030
let json = serde_json::to_string(entry)
31-
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
31+
.map_err(std::io::Error::other)?;
3232
match self {
3333
AuditWriter::Stdout => {
3434
println!("{}", json);

type-bridge-core/crates/server/src/transport/http.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ mod tests {
557557
#[tokio::test]
558558
async fn validate_valid_query() {
559559
let router = app(MockExecutor::new(), true);
560-
let clauses = serde_json::to_value(&make_simple_clauses()).unwrap();
560+
let clauses = serde_json::to_value(make_simple_clauses()).unwrap();
561561
let body = serde_json::json!({
562562
"clauses": clauses
563563
});

0 commit comments

Comments
 (0)