Skip to content

Commit 51eac40

Browse files
refactor: cleaned up and formatted search sql, added filter in the beginning
1 parent 7559b58 commit 51eac40

File tree

1 file changed

+52
-59
lines changed

1 file changed

+52
-59
lines changed

backend/src/db/queries.rs

Lines changed: 52 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -80,70 +80,63 @@ pub fn get_all_unapproved_query() -> String {
8080
format!("SELECT {} FROM iqps WHERE approve_status = false and is_deleted=false ORDER BY upload_timestamp ASC", ADMIN_DASHBOARD_QP_FIELDS)
8181
}
8282

83-
/// Searches for papers using the given query_text (parameter `$1`). This is total voodoo by Rajiv Harlalka. The second parameter can be used to filter by exam.
84-
/// // TODO: @Rajiv please update this documentation to explain the voodoo.
85-
const QP_SEARCH: &str = "
86-
with fuzzy as (
87-
select id,
88-
similarity(course_code || ' ' || course_name, $1) as sim_score,
89-
row_number() over (order by similarity(course_code || ' ' || course_name, $1) desc) as rank_ix
90-
from iqps
91-
where (course_code || ' ' || course_name) %>> $1 AND approve_status = true
92-
order by rank_ix
93-
limit 30
94-
),
95-
full_text as (
96-
select
97-
id,
98-
ts_rank_cd(fts_course_details, websearch_to_tsquery($1)) as rank_score,
99-
row_number() over(order by ts_rank_cd(fts_course_details , websearch_to_tsquery($1)) desc) as rank_ix
100-
from
101-
iqps
102-
where
103-
fts_course_details @@ websearch_to_tsquery($1)
104-
AND approve_status = true
105-
order by rank_ix
106-
limit 30
107-
),
108-
partial_search as (
109-
select id,
110-
ts_rank_cd(fts_course_details , to_tsquery('simple', websearch_to_tsquery('simple', $1)::text || ':*' )) as rank_score,
111-
row_number() over(order by ts_rank_cd(fts_course_details , to_tsquery('simple', websearch_to_tsquery('simple', $1)::text || ':*' )) desc) as rank_ix
112-
from iqps where
113-
fts_course_details @@ to_tsquery(
114-
'simple',
115-
websearch_to_tsquery('simple', $1)::text || ':*'
116-
)
117-
AND approve_status = true
118-
limit 30
119-
), result as (
120-
select
121-
iqps.id,iqps.course_code, iqps.course_name, iqps.year, iqps.exam, iqps.filelink, iqps.from_library, iqps.upload_timestamp, iqps.approve_status, iqps.semester
122-
from
123-
fuzzy
124-
full outer join full_text on fuzzy.id = full_text.id
125-
full outer join partial_search on coalesce(fuzzy.id, full_text.id) = partial_search.id
126-
join iqps on coalesce(fuzzy.id, full_text.id, partial_search.id) = iqps.id
127-
order by
128-
coalesce(1.0 / (50 + fuzzy.rank_ix), 0.0) * 1 +
129-
coalesce(1.0 / (50 + full_text.rank_ix), 0.0) * 1 +
130-
coalesce(1.0 / (50 + partial_search.rank_ix), 0.0) * 1
131-
desc
132-
)";
133-
13483
/// Returns the query for searching question papers. It is mostly voodoo, @Rajiv please update the documentation.
13584
///
13685
/// Optionally, the `exam` argument can be used to also add a clause to match the exam field.
13786
pub fn get_qp_search_query(exam: bool) -> String {
138-
let mut query = QP_SEARCH.to_owned();
139-
140-
query.push_str(&format!(" SELECT {} FROM result", SEARCH_QP_FIELDS));
87+
let exam_filter = if exam {
88+
"WHERE (exam = $2 OR exam = '')"
89+
} else {
90+
""
91+
};
14192

142-
if exam {
143-
query.push_str(" WHERE (exam = $2 or exam = '')");
144-
}
145-
146-
query
93+
format!("
94+
WITH filtered AS (
95+
SELECT * from iqps {exam_filter}
96+
),
97+
fuzzy AS (
98+
SELECT id,
99+
similarity(course_code || ' ' || course_name, $1) AS sim_score,
100+
row_number() OVER (ORDER BY similarity(course_code || ' ' || course_name, $1) DESC) AS rank_ix
101+
FROM filtered
102+
WHERE (course_code || ' ' || course_name) %>> $1 AND approve_status = true
103+
ORDER BY rank_ix
104+
LIMIT 30
105+
),
106+
full_text AS (
107+
SELECT id,
108+
ts_rank_cd(fts_course_details, websearch_to_tsquery($1)) AS rank_score,
109+
row_number() OVER (ORDER BY ts_rank_cd(fts_course_details, websearch_to_tsquery($1)) DESC) AS rank_ix
110+
FROM filtered
111+
WHERE fts_course_details @@ websearch_to_tsquery($1) AND approve_status = true
112+
ORDER BY rank_ix
113+
LIMIT 30
114+
),
115+
partial_search AS (
116+
SELECT id,
117+
ts_rank_cd(fts_course_details, {to_tsquery}) AS rank_score,
118+
row_number() OVER (ORDER BY ts_rank_cd(fts_course_details, {to_tsquery}) DESC) as rank_ix
119+
FROM filtered
120+
WHERE fts_course_details @@ {to_tsquery} AND approve_status = true
121+
LIMIT 30
122+
),
123+
result AS (
124+
SELECT {intermediate_fields}
125+
FROM fuzzy
126+
FULL OUTER JOIN full_text ON fuzzy.id = full_text.id
127+
FULL OUTER JOIN partial_search ON coalesce(fuzzy.id, full_text.id) = partial_search.id
128+
JOIN filtered ON coalesce(fuzzy.id, full_text.id, partial_search.id) = filtered.id
129+
ORDER BY
130+
coalesce(1.0 / (50 + fuzzy.rank_ix), 0.0) * 1 +
131+
coalesce(1.0 / (50 + full_text.rank_ix), 0.0) * 1 +
132+
coalesce(1.0 / (50 + partial_search.rank_ix), 0.0) * 1
133+
DESC
134+
) SELECT {search_qp_fields} FROM result",
135+
search_qp_fields = SEARCH_QP_FIELDS,
136+
to_tsquery = "to_tsquery('simple', websearch_to_tsquery('simple', $1)::text || ':*')",
137+
exam_filter = exam_filter,
138+
intermediate_fields = ADMIN_DASHBOARD_QP_FIELDS.split(", ").map(|field| format!("filtered.{}", field)).collect::<Vec<String>>().join(", ")
139+
)
147140
}
148141

149142
/// List of fields in the [`crate::db::models::DBAdminDashboardQP`] to be used with SELECT clauses

0 commit comments

Comments
 (0)