Skip to content

Commit 8e64c0b

Browse files
sgrifcarols10cents
authored andcommitted
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 6c55f02 commit 8e64c0b

File tree

3 files changed

+14
-3
lines changed

3 files changed

+14
-3
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE keywords ALTER COLUMN keyword TYPE varchar;
Lines changed: 1 addition & 0 deletions
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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,21 @@ pub fn search(req: &mut dyn Request) -> CargoResult<Response> {
9696
}
9797

9898
if let Some(kws) = params.get("all_keywords") {
99+
use diesel::sql_types::Array;
100+
sql_function!(#[aggregate] fn array_agg<T>(x: T) -> Array<T>);
101+
99102
let names: Vec<_> = kws.split_whitespace().map(|name| name.to_lowercase()).collect();
100103

101104
query = query.filter(
102-
crates::id.eq_any(
105+
// FIXME: Just use `.contains` in Diesel 2.0
106+
// https://github.com/diesel-rs/diesel/issues/2066
107+
Contains::new(
103108
crates_keywords::table
104-
.select(crates_keywords::crate_id)
105109
.inner_join(keywords::table)
106-
.filter(crate::lower(keywords::keyword).eq(any(names))),
110+
.filter(crates_keywords::crate_id.eq(crates::id))
111+
.select(array_agg(keywords::keyword))
112+
.single_value(),
113+
names.into_sql::<Array<Text>>(),
107114
),
108115
);
109116
} else if let Some(kw) = params.get("keyword") {
@@ -241,3 +248,5 @@ pub fn search(req: &mut dyn Request) -> CargoResult<Response> {
241248
},
242249
}))
243250
}
251+
252+
diesel_infix_operator!(Contains, "@>");

0 commit comments

Comments
 (0)