Skip to content

Commit bf43f91

Browse files
committed
refactor: use grades table
This patch uses the new climb "all-grades" table to interface with climbing grades.
1 parent 8afa544 commit bf43f91

File tree

3 files changed

+108
-154
lines changed

3 files changed

+108
-154
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2021"
77
async-graphql = "7.0.7"
88
async-graphql-axum = "7.0.7"
99
axum = "0.7.5"
10+
bytes = "1.10.1"
1011
config = "0.14.1"
1112
deadpool = "0.12.1"
1213
deadpool-postgres = { version = "0.14.0", features = ["serde"] }

src/schema/climb.rs

Lines changed: 42 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::str::FromStr;
2+
13
use async_graphql::{Context, Object, Result, SimpleObject, Union, ID};
24

35
use crate::schema::area::Area;
@@ -7,9 +9,6 @@ use crate::schema::vermin_grade::VerminGrade;
79
use crate::schema::yosemite_decimal_grade::YosemiteDecimalGrade;
810
use crate::AppData;
911

10-
use super::fontainebleau_grade::FontainebleauLetter;
11-
use super::yosemite_decimal_grade::YosemiteDecimalLetter;
12-
1312
#[derive(Union)]
1413
enum ClimbParent {
1514
Area(Area),
@@ -38,6 +37,35 @@ enum ClimbGrade {
3837
YosemiteDecimal(ClimbYosemiteDecimalGrade),
3938
}
4039

40+
#[derive(Debug, PartialEq, Eq)]
41+
struct ParseClimbGradeError;
42+
43+
impl FromStr for ClimbGrade {
44+
type Err = ParseClimbGradeError;
45+
46+
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
47+
VerminGrade::from_str(s)
48+
.map(|v| {
49+
ClimbGrade::Vermin(ClimbVerminGrade { value: v })
50+
})
51+
.or_else(|_| {
52+
FontainebleauGrade::from_str(s)
53+
.map(|f| {
54+
ClimbGrade::Fontainebleau(ClimbFontainebleauGrade { value: f })
55+
})
56+
})
57+
.or_else(|_| {
58+
YosemiteDecimalGrade::from_str(s)
59+
.map(|y| {
60+
ClimbGrade::YosemiteDecimal(ClimbYosemiteDecimalGrade { value: y })
61+
})
62+
})
63+
.map_err(|_| {
64+
ParseClimbGradeError
65+
})
66+
}
67+
}
68+
4169
pub struct Climb(pub i32);
4270

4371
#[Object]
@@ -89,91 +117,29 @@ impl Climb {
89117
}
90118
};
91119

92-
let verm_grades: Vec<ClimbGrade> = client
120+
let value: Vec<ClimbGrade> = client
121+
// TODO since grade doesn't implement binary functions, we must request the text
122+
// format, when grade _does_ implement these, the ::TEXT is not needed
93123
.query(
94124
"
95-
SELECT value
96-
FROM climb_verm_grades
125+
SELECT grade::TEXT
126+
FROM climb_grades
97127
WHERE climb_id = $1
98128
",
99129
&[&self.0],
100130
)
101131
.await?
102132
.into_iter()
103133
.filter_map(|row| {
104-
row.try_get::<_, i32>(0).ok().and_then(|v| {
105-
u8::try_from(v)
106-
.ok()
107-
.map(|value| ClimbGrade::Vermin(ClimbVerminGrade { value: VerminGrade(value) } ))
108-
})
109-
})
110-
.collect();
111-
112-
let font_grades: Vec<ClimbGrade> = client
113-
.query(
114-
"
115-
SELECT value, letter, plus
116-
FROM climb_font_grades
117-
WHERE climb_id = $1
118-
",
119-
&[&self.0],
120-
)
121-
.await?
122-
.into_iter()
123-
.filter_map(|row| {
124-
let number: u8 = row
125-
.try_get::<_, i32>(0)
126-
.ok()
127-
.and_then(|v| u8::try_from(v).ok())?;
128-
129-
let letter = row.try_get::<_, Option<FontainebleauLetter>>(1).ok()?;
130-
131-
let plus: bool = row.try_get(2).ok()?;
132-
133-
Some(ClimbGrade::Fontainebleau(ClimbFontainebleauGrade {
134-
value: FontainebleauGrade {
135-
number,
136-
letter,
137-
plus,
138-
},
139-
}))
140-
})
141-
.collect();
142-
143-
let yds_grades: Vec<ClimbGrade> = client
144-
.query(
145-
"
146-
SELECT value, letter
147-
FROM climb_yds_grades
148-
WHERE climb_id = $1
149-
",
150-
&[&self.0],
151-
)
152-
.await?
153-
.into_iter()
154-
.filter_map(|row| {
155-
let grade: u8 = row
156-
.try_get::<_, i32>(0)
157-
.ok()
158-
.and_then(|v| u8::try_from(v).ok())?;
159-
160-
let letter: Option<YosemiteDecimalLetter> =
161-
row.try_get::<_, Option<YosemiteDecimalLetter>>(1).ok()?;
162-
163-
Some(ClimbGrade::YosemiteDecimal(ClimbYosemiteDecimalGrade {
164-
value: YosemiteDecimalGrade {
165-
grade,
166-
letter
167-
},
168-
}))
134+
let grade_str: String = row.get(0);
135+
match grade_str.parse::<ClimbGrade>() {
136+
Ok(grade) => Some(grade),
137+
Err(_) => None,
138+
}
169139
})
170140
.collect();
171141

172-
let mut all_grades = verm_grades;
173-
all_grades.extend(font_grades);
174-
all_grades.extend(yds_grades);
175-
176-
Ok(all_grades)
142+
Ok(value)
177143
}
178144

179145
async fn parent<'a>(&self, ctx: &Context<'a>) -> Result<Option<ClimbParent>> {

src/schema/mod.rs

Lines changed: 65 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
use std::fmt::Display;
2+
13
use async_graphql::{Context, Enum, Object, OneofObject, Result, SimpleObject, Union, ID};
24

35
use area::Area;
46
use climb::Climb;
57
use fontainebleau_grade::FontainebleauGrade;
68
use formation::{Coordinate, Formation};
9+
use postgres_types::ToSql;
710
use vermin_grade::VerminGrade;
811
use yosemite_decimal_grade::YosemiteDecimalGrade;
912

@@ -18,13 +21,56 @@ pub mod yosemite_decimal_grade;
1821

1922
pub struct QueryRoot;
2023

21-
#[derive(OneofObject)]
24+
#[derive(Debug, OneofObject)]
2225
enum GradeInput {
2326
Vermin(VerminGrade),
2427
Fontainebleau(FontainebleauGrade),
2528
YosemiteDecimal(YosemiteDecimalGrade),
2629
}
2730

31+
impl Display for GradeInput {
32+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33+
match self {
34+
GradeInput::Vermin(vermin_grade) => write!(f, "{}", vermin_grade),
35+
GradeInput::Fontainebleau(fontainebleau_grade) => write!(f, "{}", fontainebleau_grade),
36+
GradeInput::YosemiteDecimal(yosemite_decimal_grade) => write!(f, "{}", yosemite_decimal_grade),
37+
}
38+
}
39+
}
40+
41+
impl ToSql for GradeInput {
42+
fn encode_format(&self, _ty: &postgres_types::Type) -> postgres_types::Format {
43+
postgres_types::Format::Text
44+
}
45+
46+
fn to_sql(&self, _: &postgres_types::Type, out: &mut bytes::BytesMut) -> std::result::Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>>
47+
where
48+
Self: Sized
49+
{
50+
let encoded = self.to_string();
51+
out.extend_from_slice(encoded.as_bytes());
52+
Ok(postgres_types::IsNull::No)
53+
}
54+
55+
fn accepts(ty: &postgres_types::Type) -> bool
56+
where
57+
Self: Sized
58+
{
59+
matches!(ty.name(), "grade")
60+
}
61+
62+
fn to_sql_checked(
63+
&self,
64+
ty: &postgres_types::Type,
65+
out: &mut bytes::BytesMut,
66+
) -> std::result::Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> {
67+
if !Self::accepts(ty) {
68+
return Err("Unsupported PostgreSQL type".into());
69+
}
70+
self.to_sql(ty, out)
71+
}
72+
}
73+
2874
#[derive(Enum, Clone, Copy, PartialEq, Eq)]
2975
enum GradeOperation {
3076
Add,
@@ -888,44 +934,15 @@ impl MutationRoot {
888934
}
889935
};
890936

891-
match grade {
892-
GradeInput::Vermin(VerminGrade(value)) => {
893-
client
894-
.execute(
895-
"
896-
INSERT INTO climb_verm_grades (climb_id, value)
897-
VALUES ($1, $2) ON CONFLICT DO NOTHING
898-
",
899-
&[&id, &(value as i32)],
900-
)
901-
.await?;
902-
}
903-
GradeInput::Fontainebleau(FontainebleauGrade {
904-
number,
905-
letter,
906-
plus,
907-
}) => {
908-
client
909-
.execute(
910-
"
911-
INSERT INTO climb_font_grades (climb_id, value, letter, plus)
912-
VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING
913-
",
914-
&[&id, &(number as i32), &letter, &plus],
915-
)
916-
.await?;
917-
}
918-
GradeInput::YosemiteDecimal(YosemiteDecimalGrade { grade, letter }) => {
919-
client
920-
.execute(
921-
"INSERT INTO climb_yds_grades (climb_id, value, letter)
922-
VALUES ($1, $2, $3) ON CONFLICT DO NOTHING
923-
",
924-
&[&id, &(grade as i32), &letter],
925-
)
926-
.await?;
927-
}
928-
}
937+
client
938+
.execute(
939+
"
940+
INSERT INTO climb_grades (climb_id, grade)
941+
VALUES ($1, $2) ON CONFLICT DO NOTHING
942+
",
943+
&[&id, &(grade)],
944+
)
945+
.await?;
929946

930947
Ok(Climb(id))
931948
}
@@ -945,45 +962,15 @@ impl MutationRoot {
945962
}
946963
};
947964

948-
match grade {
949-
GradeInput::Vermin(VerminGrade(number)) => {
950-
client
951-
.execute(
952-
"
953-
DELETE FROM climb_verm_grades
954-
WHERE climb_id = $1 AND value = $2
955-
",
956-
&[&id, &(number as i32)],
957-
)
958-
.await?;
959-
}
960-
GradeInput::Fontainebleau(FontainebleauGrade {
961-
number,
962-
letter,
963-
plus,
964-
}) => {
965-
client
966-
.execute(
967-
"
968-
DELETE FROM climb_font_grades
969-
WHERE climb_id = $1 AND value = $2 AND (letter IS NOT DISTINCT FROM $3) AND plus = $4
970-
",
971-
&[&id, &(number as i32), &letter, &plus],
972-
)
973-
.await?;
974-
}
975-
GradeInput::YosemiteDecimal(YosemiteDecimalGrade { grade, letter }) => {
976-
client
977-
.execute(
978-
"
979-
DELETE FROM climb_yds_grades
980-
WHERE climb_id = $1 AND value = $2 AND (letter IS NOT DISTINCT FROM $3)
981-
",
982-
&[&id, &(grade as i32), &letter],
983-
)
984-
.await?;
985-
}
986-
}
965+
client
966+
.execute(
967+
"
968+
DELETE FROM climb_grades
969+
WHERE climb_id = $1 AND grade = $2
970+
",
971+
&[&id, &(grade)],
972+
)
973+
.await?;
987974

988975
Ok(Climb(id))
989976
}

0 commit comments

Comments
 (0)