Skip to content

Commit eff41c2

Browse files
authored
serve challenges following insertion order (#240) (#241)
1 parent 6076317 commit eff41c2

File tree

15 files changed

+101
-61
lines changed

15 files changed

+101
-61
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/api/v0.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ paths:
152152
summary: Get all available challenges
153153
tags: [challenge]
154154
description: |
155-
Lists all available challenges.
155+
Lists all available challenges following insertion order.
156156
responses:
157157
"200":
158158
description: Valid response

vit-servicing-station-cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ rand = "0.7.3"
1616
r2d2 = "0.8"
1717
structopt = "0.3.14"
1818
serde = { version = "1.0", features = ["derive"] }
19+
serde_json = "1"
1920
tempfile = "3.1.0"
2021
thiserror = "1.0"
2122
vit-servicing-station-lib = { path = "../vit-servicing-station-lib" }

vit-servicing-station-cli/src/csv/loaders.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::db_utils::{backup_db_file, restore_db_file};
22
use crate::{db_utils::db_file_exists, task::ExecTask};
33
use csv::Trim;
44
use serde::de::DeserializeOwned;
5-
use std::collections::HashMap;
65
use std::convert::TryInto;
76
use std::io;
87
use std::path::{Path, PathBuf};
@@ -14,7 +13,7 @@ use vit_servicing_station_lib::db::models::proposals::{
1413
};
1514
use vit_servicing_station_lib::db::{
1615
load_db_connection_pool,
17-
models::{challenges::Challenge, funds::Fund, proposals::Proposal, voteplans::Voteplan},
16+
models::{funds::Fund, proposals::Proposal, voteplans::Voteplan},
1817
};
1918

2019
#[derive(Error, Debug)]
@@ -107,11 +106,8 @@ impl CsvDataCmd {
107106
let funds = CsvDataCmd::load_from_csv::<Fund>(funds_path)?;
108107

109108
let mut voteplans = CsvDataCmd::load_from_csv::<Voteplan>(voteplans_path)?;
110-
let mut challenges: HashMap<i32, Challenge> =
111-
CsvDataCmd::load_from_csv::<Challenge>(challenges_path)?
112-
.into_iter()
113-
.map(|c| (c.id, c))
114-
.collect();
109+
let mut challenges =
110+
CsvDataCmd::load_from_csv::<super::models::Challenge>(challenges_path)?;
115111
let csv_proposals = CsvDataCmd::load_from_csv::<super::models::Proposal>(proposals_path)?;
116112
let reviews = CsvDataCmd::load_from_csv::<super::models::AdvisorReview>(reviews_path)?
117113
.into_iter()
@@ -125,7 +121,8 @@ impl CsvDataCmd {
125121

126122
for proposal in csv_proposals {
127123
let challenge_type = challenges
128-
.get(&proposal.challenge_id)
124+
.iter()
125+
.find(|c| proposal.challenge_id == c.id)
129126
.ok_or_else(|| {
130127
std::io::Error::new(
131128
std::io::ErrorKind::InvalidData,
@@ -181,7 +178,7 @@ impl CsvDataCmd {
181178
}
182179

183180
// apply fund id to challenges
184-
for challenge in challenges.values_mut() {
181+
for challenge in challenges.iter_mut() {
185182
challenge.fund_id = fund.id;
186183
}
187184

@@ -212,7 +209,10 @@ impl CsvDataCmd {
212209
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{}", e)))?;
213210

214211
vit_servicing_station_lib::db::queries::challenges::batch_insert_challenges(
215-
&challenges.values().cloned().collect::<Vec<Challenge>>(),
212+
&challenges
213+
.into_iter()
214+
.map(|c| c.into_db_challenge_values())
215+
.collect::<Vec<_>>(),
216216
&db_conn,
217217
)
218218
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{}", e)))?;

vit-servicing-station-cli/src/csv/models.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,33 @@
1+
use diesel::{ExpressionMethods, Insertable};
12
use serde::Deserialize;
23
use std::convert::TryInto;
4+
use vit_servicing_station_lib::db::models::challenges::{
5+
Challenge as DbChallenge, ChallengeHighlights,
6+
};
37
use vit_servicing_station_lib::db::models::community_advisors_reviews::{self, ReviewRanking};
48
use vit_servicing_station_lib::db::models::proposals::{
59
self, community_choice, simple, Category, ChallengeType, ProposalChallengeInfo, Proposer,
610
};
711
use vit_servicing_station_lib::db::models::vote_options::VoteOptions;
12+
use vit_servicing_station_lib::db::schema::challenges;
13+
14+
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
15+
pub struct Challenge {
16+
pub id: i32,
17+
#[serde(alias = "challengeType")]
18+
pub challenge_type: ChallengeType,
19+
pub title: String,
20+
pub description: String,
21+
#[serde(alias = "rewardsTotal")]
22+
pub rewards_total: i64,
23+
#[serde(alias = "proposersRewards")]
24+
pub proposers_rewards: i64,
25+
#[serde(alias = "fundId")]
26+
pub fund_id: i32,
27+
#[serde(alias = "challengeUrl")]
28+
pub challenge_url: String,
29+
pub highlights: Option<ChallengeHighlights>,
30+
}
831

932
#[derive(Deserialize, PartialEq, Eq, Debug, Clone)]
1033
pub struct Proposal {
@@ -104,6 +127,25 @@ fn default_challenge_id() -> i32 {
104127
-1
105128
}
106129

130+
impl Challenge {
131+
pub fn into_db_challenge_values(
132+
self,
133+
) -> <DbChallenge as Insertable<challenges::table>>::Values {
134+
(
135+
challenges::id.eq(self.id),
136+
challenges::challenge_type.eq(self.challenge_type.to_string()),
137+
challenges::title.eq(self.title),
138+
challenges::description.eq(self.description),
139+
challenges::rewards_total.eq(self.rewards_total),
140+
challenges::proposers_rewards.eq(self.proposers_rewards),
141+
challenges::fund_id.eq(self.fund_id),
142+
challenges::challenge_url.eq(self.challenge_url),
143+
// This should always be a valid json
144+
challenges::highlights.eq(serde_json::to_string(&self.highlights).ok()),
145+
)
146+
}
147+
}
148+
107149
impl Proposal {
108150
pub fn into_db_proposal_and_challenge_info(
109151
self,

vit-servicing-station-lib/migrations/2020-05-22-112032_setup_db/up.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ create table api_tokens
8484

8585
create table challenges
8686
(
87-
id INTEGER NOT NULL
87+
internal_id INTEGER NOT NULL
8888
primary key autoincrement,
89+
id INTEGER NOT NULL UNIQUE,
8990
challenge_type VARCHAR NOT NULL,
9091
title VARCHAR NOT NULL,
9192
description VARCHAR NOT NULL,

vit-servicing-station-lib/src/db/models/challenges.rs

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ pub struct ChallengeHighlights {
1010

1111
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
1212
pub struct Challenge {
13+
#[serde(alias = "internalId")]
14+
// this is used only to retain the original insert order
15+
pub internal_id: i32,
1316
pub id: i32,
1417
#[serde(alias = "challengeType")]
1518
pub challenge_type: ChallengeType,
@@ -28,38 +31,41 @@ pub struct Challenge {
2831

2932
impl Queryable<challenges::SqlType, Db> for Challenge {
3033
type Row = (
31-
// 0 -> id
34+
// 0 -> internal_id
3235
i32,
33-
// 1 -> challenge_type
36+
// 1 -> id
37+
i32,
38+
// 2 -> challenge_type
3439
String,
35-
// 1 -> title
40+
// 3 -> title
3641
String,
37-
// 2 -> description
42+
// 4 -> description
3843
String,
39-
// 3 -> rewards_total
44+
// 5 -> rewards_total
4045
i64,
41-
// 4 -> proposers_rewards
46+
// 6 -> proposers_rewards
4247
i64,
43-
// 5 -> fund_id
48+
// 7 -> fund_id
4449
i32,
45-
// 6 -> fund_url
50+
// 8 -> fund_url
4651
String,
47-
// 7 -> challenge_highlights
52+
// 9 -> challenge_highlights
4853
Option<String>,
4954
);
5055

5156
fn build(row: Self::Row) -> Self {
5257
Challenge {
53-
id: row.0,
54-
challenge_type: row.1.parse().unwrap(),
55-
title: row.2,
56-
description: row.3,
57-
rewards_total: row.4,
58-
proposers_rewards: row.5,
59-
fund_id: row.6,
60-
challenge_url: row.7,
58+
internal_id: row.0,
59+
id: row.1,
60+
challenge_type: row.2.parse().unwrap(),
61+
title: row.3,
62+
description: row.4,
63+
rewards_total: row.5,
64+
proposers_rewards: row.6,
65+
fund_id: row.7,
66+
challenge_url: row.8,
6167
// It should be ensured that the content is valid json
62-
highlights: row.8.and_then(|v| serde_json::from_str(&v).ok()),
68+
highlights: row.9.and_then(|v| serde_json::from_str(&v).ok()),
6369
}
6470
}
6571
}
@@ -104,6 +110,7 @@ pub mod test {
104110
const CHALLENGE_ID: i32 = 9001;
105111
const REWARDS_TOTAL: i64 = 100500;
106112
Challenge {
113+
internal_id: 1,
107114
id: CHALLENGE_ID,
108115
challenge_type: ChallengeType::CommunityChoice,
109116
title: "challenge title".to_string(),

vit-servicing-station-lib/src/db/queries/challenges.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ use crate::{
77
},
88
v0::errors::HandleError,
99
};
10-
use diesel::{ExpressionMethods, Insertable, QueryResult, RunQueryDsl};
10+
use diesel::{ExpressionMethods, Insertable, QueryDsl, QueryResult, RunQueryDsl};
1111

1212
pub async fn query_all_challenges(pool: &DbConnectionPool) -> Result<Vec<Challenge>, HandleError> {
1313
let db_conn = pool.get().map_err(HandleError::DatabaseError)?;
1414
tokio::task::spawn_blocking(move || {
15-
challenges_dsl::challenges
16-
.load::<Challenge>(&db_conn)
17-
.map_err(|_| HandleError::InternalError("Error retrieving challenges".to_string()))
15+
diesel::QueryDsl::order_by(
16+
challenges_dsl::challenges,
17+
challenges::dsl::internal_id.asc(),
18+
)
19+
.load::<Challenge>(&db_conn)
20+
.map_err(|_| HandleError::InternalError("Error retrieving challenges".to_string()))
1821
})
1922
.await
2023
.map_err(|_e| HandleError::InternalError("Error executing request".to_string()))?
@@ -44,6 +47,7 @@ pub async fn query_challenges_by_fund_id(
4447
challenges_dsl::challenges,
4548
challenges_dsl::fund_id.eq(fund_id),
4649
)
50+
.order_by(challenges::dsl::internal_id.asc())
4751
.load::<Challenge>(&db_conn)
4852
.map_err(|_e| HandleError::NotFound("Error loading challenges for fund id".to_string()))
4953
})
@@ -69,16 +73,10 @@ pub async fn query_challenge_proposals_by_id(
6973
}
7074

7175
pub fn batch_insert_challenges(
72-
challenges_slice: &[Challenge],
76+
challenges: &[<Challenge as Insertable<challenges::table>>::Values],
7377
db_conn: &DbConnection,
7478
) -> QueryResult<usize> {
7579
diesel::insert_into(challenges::table)
76-
.values(
77-
challenges_slice
78-
.iter()
79-
.cloned()
80-
.map(|challenge| challenge.values())
81-
.collect::<Vec<_>>(),
82-
)
80+
.values(challenges)
8381
.execute(db_conn)
8482
}

vit-servicing-station-lib/src/db/schema.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ table! {
88

99
table! {
1010
challenges (id) {
11+
internal_id -> Integer,
1112
id -> Integer,
1213
challenge_type -> Text,
1314
title -> Text,

vit-servicing-station-tests/src/common/data/generator/arbitrary/snapshot_generator.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ impl ArbitrarySnapshotGenerator {
266266

267267
vec![
268268
Challenge {
269+
internal_id: first_challenge.internal_id,
269270
id: simple_id.abs(),
270271
challenge_type: ChallengeType::Simple,
271272
title: first_challenge.title,
@@ -277,6 +278,7 @@ impl ArbitrarySnapshotGenerator {
277278
highlights: self.template_generator.gen_highlights(),
278279
},
279280
Challenge {
281+
internal_id: second_challenge.internal_id,
280282
id: community_choice_id.abs(),
281283
challenge_type: ChallengeType::CommunityChoice,
282284
title: second_challenge.title,
@@ -295,6 +297,7 @@ impl ArbitrarySnapshotGenerator {
295297
let challenge = self.template_generator.next_challenge();
296298

297299
Challenge {
300+
internal_id: challenge.internal_id,
298301
id: id.abs(),
299302
challenge_type: ChallengeType::CommunityChoice,
300303
title: challenge.title,

0 commit comments

Comments
 (0)