1+ use rand:: seq:: SliceRandom ;
2+ use rand:: thread_rng;
13use vit_servicing_station_lib:: db:: models:: proposals:: FullProposalInfo ;
24use vit_servicing_station_lib:: v0:: endpoints:: search:: requests:: * ;
35use vit_servicing_station_lib:: { db:: models:: challenges:: Challenge , v0:: result:: HandlerResult } ;
@@ -13,14 +15,6 @@ fn make_error(s: &str, code: u16) -> Rejection {
1315 } )
1416}
1517
16- fn challenge_field_error ( ) -> Rejection {
17- make_error ( "`challenge` doesn't support `funds` or `author`" , 400 )
18- }
19-
20- fn proposal_field_error ( ) -> Rejection {
21- make_error ( "`proposal` doesn't support `type`" , 400 )
22- }
23-
2418fn mock_order_by_error ( ) -> Rejection {
2519 make_error ( "Mock implementation only supports 0 or 1 `order_by`s" , 400 )
2620}
@@ -73,181 +67,176 @@ async fn search_impl(
7367 } ;
7468 match table {
7569 Table :: Challenges => {
76- if filter. iter ( ) . any ( |c| {
77- matches ! (
78- c,
79- Constraint :: Text {
80- column: Column :: Funds | Column :: Author ,
81- ..
82- }
83- )
84- } ) {
85- return Err ( challenge_field_error ( ) ) ;
86- }
87-
88- if matches ! (
89- order_by,
90- Some ( OrderBy :: Column {
91- column: Column :: Funds | Column :: Author ,
92- ..
93- } )
94- ) {
95- return Err ( challenge_field_error ( ) ) ;
96- }
97-
98- let ctx = context. read ( ) . unwrap ( ) ;
99- let challenges = ctx. state ( ) . vit ( ) . challenges ( ) ;
100- let result = search_challenges ( challenges, & filter, order_by) ;
101- let result = limit_and_offset ( result, limit, offset) ;
102- Ok ( SearchResponse :: Challenge ( result) )
70+ let results = context. read ( ) . unwrap ( ) . state ( ) . vit ( ) . challenges ( ) ;
71+ let results = filter_challenges ( results, & filter) ?;
72+ let results = sort_challenges ( results, order_by) ;
73+ let results = limit_and_offset ( results, limit, offset) ;
74+ Ok ( SearchResponse :: Challenge ( results) )
10375 }
10476 Table :: Proposals => {
105- if filter. iter ( ) . any ( |c| {
106- matches ! (
107- c,
108- Constraint :: Text {
109- column: Column :: Type ,
110- ..
111- }
112- )
113- } ) {
114- return Err ( proposal_field_error ( ) ) ;
115- }
77+ let results = context. read ( ) . unwrap ( ) . state ( ) . vit ( ) . proposals ( ) ;
78+ let results = filter_proposals ( results, & filter) ?;
79+ let results = sort_proposals ( results, order_by) ;
80+ let results = limit_and_offset ( results, limit, offset) ;
81+ Ok ( SearchResponse :: Proposal ( results) )
82+ }
83+ }
84+ }
11685
117- if filter. iter ( ) . any ( |c| {
118- matches ! (
119- c,
120- Constraint :: Text {
121- column: Column :: Funds ,
122- ..
123- }
124- )
125- } ) {
126- return Err ( proposal_field_error ( ) ) ;
86+ fn filter_challenges (
87+ mut challenges : Vec < Challenge > ,
88+ filter : & [ Constraint ] ,
89+ ) -> Result < Vec < Challenge > , Rejection > {
90+ for f in filter {
91+ use Column :: * ;
92+ match f {
93+ Constraint :: Text { search, column } => {
94+ let search = search. to_lowercase ( ) ;
95+ let string_function = match column {
96+ Type => |c : & Challenge | c. challenge_type . to_string ( ) ,
97+ Title => |c : & Challenge | c. title . clone ( ) ,
98+ Desc => |c : & Challenge | c. description . clone ( ) ,
99+ Author | Funds | ImpactScore => return Err ( make_error ( "invalid column" , 400 ) ) ,
100+ } ;
101+
102+ challenges. retain ( |c| string_function ( c) . to_lowercase ( ) . contains ( & search) )
127103 }
128-
129- if matches ! (
130- order_by,
131- Some ( OrderBy :: Column {
132- column: Column :: Type ,
133- ..
134- } )
135- ) {
136- return Err ( make_error ( "can't search proposal by `fund`" , 400 ) ) ;
104+ Constraint :: Range {
105+ lower,
106+ upper,
107+ column,
108+ } => {
109+ let lower = lower. unwrap_or ( i64:: MIN ) ;
110+ let upper = upper. unwrap_or ( i64:: MAX ) ;
111+
112+ let num_function = match column {
113+ Funds => |c : & Challenge | c. rewards_total ,
114+ _ => return Err ( make_error ( "invalid column" , 400 ) ) ,
115+ } ;
116+
117+ challenges. retain ( |c| {
118+ let num = num_function ( c) ;
119+ lower <= num && num <= upper
120+ } ) ;
137121 }
138-
139- let ctx = context. read ( ) . unwrap ( ) ;
140- let proposals = ctx. state ( ) . vit ( ) . proposals ( ) ;
141- let result = search_proposals ( proposals, & filter, order_by) ;
142- let result = limit_and_offset ( result, limit, offset) ;
143- Ok ( SearchResponse :: Proposal ( result) )
144122 }
145123 }
124+
125+ Ok ( challenges)
146126}
147127
148- fn limit_and_offset < T > ( vec : Vec < T > , limit : Option < u64 > , offset : Option < u64 > ) -> Vec < T > {
149- let offset = offset. unwrap_or ( 0 ) ;
150- let limit = limit. unwrap_or ( u64:: MAX ) ;
151- vec. into_iter ( )
152- . skip ( offset as usize )
153- . take ( limit as usize )
154- . collect ( )
128+ fn sort_challenges ( mut challenges : Vec < Challenge > , order_by : Option < OrderBy > ) -> Vec < Challenge > {
129+ match order_by {
130+ None => { }
131+ Some ( OrderBy :: Random ) => challenges. shuffle ( & mut thread_rng ( ) ) ,
132+ Some ( OrderBy :: Column { column, descending } ) => {
133+ match column {
134+ Column :: Type => challenges. sort_by ( |a, b| {
135+ a. challenge_type
136+ . to_string ( )
137+ . cmp ( & b. challenge_type . to_string ( ) )
138+ } ) ,
139+ Column :: Desc => challenges. sort_by ( |a, b| a. description . cmp ( & b. description ) ) ,
140+ Column :: Title => challenges. sort_by ( |a, b| a. title . cmp ( & b. title ) ) ,
141+ _ => { }
142+ }
143+
144+ if descending {
145+ challenges. reverse ( ) ;
146+ }
147+ }
148+ } ;
149+
150+ challenges
155151}
156152
157- fn search_proposals (
153+ fn filter_proposals (
158154 mut proposals : Vec < FullProposalInfo > ,
159155 filter : & [ Constraint ] ,
160- order_by : Option < OrderBy > ,
161- ) -> Vec < FullProposalInfo > {
162- fn is_match ( proposal : & FullProposalInfo , constraint : & Constraint ) -> bool {
163- let Constraint :: Text { column, search } = constraint else { todo ! ( ) } ;
164- let string = match column {
165- Column :: Desc => & proposal. proposal . proposal_summary ,
166- Column :: Title => & proposal. proposal . proposal_title ,
167- Column :: Author => & proposal. proposal . proposer . proposer_name ,
168- _ => return false ,
169- } ;
170-
171- string. to_lowercase ( ) . contains ( & search. to_lowercase ( ) )
172- }
173-
174- let should_retain = |p : & FullProposalInfo | filter. iter ( ) . all ( |cons| is_match ( p, cons) ) ;
175- proposals. retain ( should_retain) ;
176-
177- if let Some ( OrderBy :: Column { column, descending } ) = order_by {
178- match column {
179- Column :: Desc => proposals. sort_by ( |a, b| {
180- a. proposal
181- . proposal_summary
182- . cmp ( & b. proposal . proposal_summary )
183- } ) ,
184- Column :: Title => {
185- proposals. sort_by ( |a, b| a. proposal . proposal_title . cmp ( & b. proposal . proposal_title ) )
156+ ) -> Result < Vec < FullProposalInfo > , Rejection > {
157+ for f in filter {
158+ use Column :: * ;
159+ match f {
160+ Constraint :: Text { search, column } => {
161+ let search = search. to_lowercase ( ) ;
162+ let string_function = match column {
163+ Type => |p : & FullProposalInfo | p. challenge_type . to_string ( ) ,
164+ Title => |p : & FullProposalInfo | p. proposal . proposal_title . clone ( ) ,
165+ Desc => |p : & FullProposalInfo | p. proposal . proposal_summary . clone ( ) ,
166+ Author => |p : & FullProposalInfo | p. proposal . proposer . proposer_name . clone ( ) ,
167+ Funds | ImpactScore => return Err ( make_error ( "invalid column" , 400 ) ) ,
168+ } ;
169+
170+ proposals. retain ( |p| string_function ( p) . to_lowercase ( ) . contains ( & search) )
186171 }
187- Column :: Funds => {
188- proposals. sort_by ( |a, b| a. proposal . proposal_funds . cmp ( & b. proposal . proposal_funds ) )
172+ Constraint :: Range {
173+ lower,
174+ upper,
175+ column,
176+ } => {
177+ let lower = lower. unwrap_or ( i64:: MIN ) ;
178+ let upper = upper. unwrap_or ( i64:: MAX ) ;
179+
180+ let num_function = match column {
181+ Funds => |p : & FullProposalInfo | p. proposal . proposal_funds ,
182+ ImpactScore => |p : & FullProposalInfo | p. proposal . proposal_impact_score ,
183+ _ => return Err ( make_error ( "invalid column" , 400 ) ) ,
184+ } ;
185+
186+ proposals. retain ( |p| {
187+ let num = num_function ( p) ;
188+ lower <= num && num <= upper
189+ } ) ;
189190 }
190- Column :: Author => proposals. sort_by ( |a, b| {
191- a. proposal
192- . proposer
193- . proposer_name
194- . cmp ( & b. proposal . proposer . proposer_name )
195- } ) ,
196- _ => { }
197- } ;
198-
199- if descending {
200- proposals. reverse ( ) ;
201191 }
202192 }
203193
204- proposals
194+ Ok ( proposals)
205195}
206196
207- fn search_challenges (
208- mut challenges : Vec < Challenge > ,
209- filter : & [ Constraint ] ,
197+ fn sort_proposals (
198+ mut proposals : Vec < FullProposalInfo > ,
210199 order_by : Option < OrderBy > ,
211- ) -> Vec < Challenge > {
212- fn is_match ( challenge : & Challenge , constraint : & Constraint ) -> bool {
213- let Constraint :: Text { search, column } = constraint else { todo ! ( ) } ;
214- let string = match column {
215- Column :: Type => {
216- return challenge
217- . challenge_type
218- . to_string ( )
219- . to_lowercase ( )
220- . contains ( & challenge. challenge_type . to_string ( ) )
200+ ) -> Vec < FullProposalInfo > {
201+ match order_by {
202+ None => { }
203+ Some ( OrderBy :: Random ) => proposals. shuffle ( & mut thread_rng ( ) ) ,
204+ Some ( OrderBy :: Column { column, descending } ) => {
205+ match column {
206+ Column :: Desc => proposals. sort_by ( |a, b| {
207+ a. proposal
208+ . proposal_summary
209+ . cmp ( & b. proposal . proposal_summary )
210+ } ) ,
211+ Column :: Title => proposals
212+ . sort_by ( |a, b| a. proposal . proposal_title . cmp ( & b. proposal . proposal_title ) ) ,
213+ Column :: Funds => proposals
214+ . sort_by ( |a, b| a. proposal . proposal_funds . cmp ( & b. proposal . proposal_funds ) ) ,
215+ Column :: Author => proposals. sort_by ( |a, b| {
216+ a. proposal
217+ . proposer
218+ . proposer_name
219+ . cmp ( & b. proposal . proposer . proposer_name )
220+ } ) ,
221+ _ => { }
222+ } ;
223+
224+ if descending {
225+ proposals. reverse ( ) ;
221226 }
222- Column :: Desc => & challenge. description ,
223- Column :: Title => & challenge. title ,
224- _ => return false ,
225- } ;
226-
227- string. to_lowercase ( ) . contains ( & search. to_lowercase ( ) )
228- }
229-
230- let should_retain = |c : & Challenge | filter. iter ( ) . all ( |cons| is_match ( c, cons) ) ;
231- challenges. retain ( should_retain) ;
232-
233- if let Some ( OrderBy :: Column { column, descending } ) = order_by {
234- match column {
235- Column :: Type => challenges. sort_by ( |a, b| {
236- a. challenge_type
237- . to_string ( )
238- . cmp ( & b. challenge_type . to_string ( ) )
239- } ) ,
240- Column :: Desc => challenges. sort_by ( |a, b| a. description . cmp ( & b. description ) ) ,
241- Column :: Title => challenges. sort_by ( |a, b| a. title . cmp ( & b. title ) ) ,
242- _ => { }
243- }
244-
245- if descending {
246- challenges. reverse ( ) ;
247227 }
248228 }
249229
250- challenges
230+ proposals
231+ }
232+
233+ fn limit_and_offset < T > ( vec : Vec < T > , limit : Option < u64 > , offset : Option < u64 > ) -> Vec < T > {
234+ let offset = offset. unwrap_or ( 0 ) ;
235+ let limit = limit. unwrap_or ( u64:: MAX ) ;
236+ vec. into_iter ( )
237+ . skip ( offset as usize )
238+ . take ( limit as usize )
239+ . collect ( )
251240}
252241
253242#[ cfg( test) ]
0 commit comments