Skip to content

Commit 316002d

Browse files
committed
Add a working "matches all keywords" query.
Diesel has a bug where array expression methods aren't implemented on nullable expressions, so we can't just call Diesel's `.contains` method until the fix lands. I've added a workaround for the time being. This results in a runtime error since `keyword` was defined as `varchar`, which coerces to `text`, but arrays do not. I've changed the column type to address this. The keywords table is small enough and read infrequently enough that I'm not concerned about the exclusive lock in this migration.
1 parent f1138d7 commit 316002d

File tree

3 files changed

+15
-4
lines changed

3 files changed

+15
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE keywords ALTER COLUMN keyword TYPE varchar;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE keywords ALTER COLUMN keyword TYPE text;

src/controllers/krate/search.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,21 @@ pub fn search(req: &mut dyn Request) -> CargoResult<Response> {
101101

102102
if let Some(kws) = params.get_all("keyword") {
103103
has_filter = true;
104-
use diesel::dsl::any;
104+
105+
use diesel::sql_types::Array;
106+
sql_function!(#[aggregate] fn array_agg<T>(x: T) -> Array<T>);
107+
105108
let names: Vec<_> = kws.iter().map(|name| name.to_lowercase()).collect();
106109
query = query.filter(
107-
crates::id.eq_any(
110+
// FIXME: Just use `.contains` in Diesel 2.0
111+
// https://github.com/diesel-rs/diesel/issues/2066
112+
Contains::new(
108113
crates_keywords::table
109-
.select(crates_keywords::crate_id)
110114
.inner_join(keywords::table)
111-
.filter(crate::lower(keywords::keyword).eq(any(names))),
115+
.filter(crates_keywords::crate_id.eq(crates::id))
116+
.select(array_agg(keywords::keyword))
117+
.single_value(),
118+
names.into_sql::<Array<Text>>(),
112119
),
113120
);
114121
} else if let Some(letter) = params.get("letter") {
@@ -239,3 +246,5 @@ pub fn search(req: &mut dyn Request) -> CargoResult<Response> {
239246
meta: Meta { total },
240247
}))
241248
}
249+
250+
diesel_infix_operator!(Contains, "@>");

0 commit comments

Comments
 (0)