Skip to content

Commit

Permalink
Merge pull request #2378 from dathere/2377-joinp_right-anti_right-semi
Browse files Browse the repository at this point in the history
feat: `joinp` add `--right-anti` and `--right-semi` options
  • Loading branch information
jqnatividad authored Dec 25, 2024
2 parents f63864e + aaba8b0 commit 6e3532d
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 8 deletions.
45 changes: 37 additions & 8 deletions src/cmd/joinp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ joinp options:
corresponding row in the first data set. When no
corresponding row exists, it is padded out with
empty fields. (This is the reverse of 'outer left'.)
--right-anti This returns only the rows in the second CSV data set
that do not have a corresponding row in the first
data set. The output schema is the same as the
second dataset.
--right-semi This returns only the rows in the second CSV data set
that have a corresponding row in the first data set.
The output schema is the same as the second data set.
--full Do a 'full outer' join. This returns all rows in
both data sets with matching records joined. If
there is no match, the missing side will be padded
Expand Down Expand Up @@ -208,6 +215,7 @@ use std::{
env,
fs::File,
io::{self, BufReader, BufWriter, Read, Write},
mem::swap,
path::{Path, PathBuf},
str,
};
Expand All @@ -231,6 +239,8 @@ struct Args {
flag_left_anti: bool,
flag_left_semi: bool,
flag_right: bool,
flag_right_anti: bool,
flag_right_semi: bool,
flag_full: bool,
flag_cross: bool,
flag_coalesce: bool,
Expand Down Expand Up @@ -311,40 +321,59 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
args.flag_left_anti,
args.flag_left_semi,
args.flag_right,
args.flag_right_anti,
args.flag_right_semi,
args.flag_full,
args.flag_cross,
args.flag_asof,
) {
// default inner join
(false, false, false, false, false, false, false) => {
(false, false, false, false, false, false, false, false, false) => {
join.run(JoinType::Inner, validation, maintain_order, false)
},
// left join
(true, false, false, false, false, false, false) => {
(true, false, false, false, false, false, false, false, false) => {
join.run(JoinType::Left, validation, maintain_order, false)
},
// left anti join
(false, true, false, false, false, false, false) => {
(false, true, false, false, false, false, false, false, false) => {
join.run(JoinType::Anti, validation, maintain_order, false)
},
// left semi join
(false, false, true, false, false, false, false) => {
(false, false, true, false, false, false, false, false, false) => {
join.run(JoinType::Semi, validation, maintain_order, false)
},
// right join
(false, false, false, true, false, false, false) => {
(false, false, false, true, false, false, false, false, false) => {
join.run(JoinType::Right, validation, maintain_order, false)
},
// right anti join
// swap left and right data sets and run left anti join
(false, false, false, false, true, false, false, false, false) => {
let mut swapped_join = join;
swap(&mut swapped_join.left_lf, &mut swapped_join.right_lf);
swap(&mut swapped_join.left_sel, &mut swapped_join.right_sel);
swapped_join.run(JoinType::Anti, validation, maintain_order, false)
},
// right semi join
// swap left and right data sets and run left semi join
(false, false, false, false, false, true, false, false, false) => {
let mut swapped_join = join;
swap(&mut swapped_join.left_lf, &mut swapped_join.right_lf);
swap(&mut swapped_join.left_sel, &mut swapped_join.right_sel);
swapped_join.run(JoinType::Semi, validation, maintain_order, false)
},
// full join
(false, false, false, false, true, false, false) => {
(false, false, false, false, false, false, true, false, false) => {
join.run(JoinType::Full, validation, maintain_order, false)
},
// cross join
(false, false, false, false, false, true, false) => {
(false, false, false, false, false, false, false, true, false) => {
join.run(JoinType::Cross, validation, MaintainOrderJoin::None, false)
},

// as of join
(false, false, false, false, false, false, true) => {
(false, false, false, false, false, false, false, false, true) => {
// safety: flag_strategy is always is_some() as it has a default value
args.flag_strategy = Some(args.flag_strategy.unwrap().to_lowercase());
let strategy = match args.flag_strategy.as_deref() {
Expand Down
75 changes: 75 additions & 0 deletions tests/test_joinp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1738,3 +1738,78 @@ fn test_joinp_cache_schema() {
.arg("2");
wrk.assert_err(&mut cmd);
}

joinp_test!(
joinp_right_semi,
|wrk: Workdir, mut cmd: process::Command| {
cmd.arg("--right-semi");
let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
let expected = vec![
svec!["city", "place"],
svec!["Boston", "Logan Airport"],
svec!["Boston", "Boston Garden"],
svec!["Buffalo", "Ralph Wilson Stadium"],
];
assert_eq!(got, expected);
}
);

joinp_test_tab!(
joinp_right_semi_tab,
|wrk: Workdir, mut cmd: process::Command| {
cmd.arg("--right-semi");
let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
let expected = vec![
svec!["city", "place"],
svec!["Boston", "Logan Airport"],
svec!["Boston", "Boston Garden"],
svec!["Buffalo", "Ralph Wilson Stadium"],
];
assert_eq!(got, expected);
}
);

joinp_test_comments!(
joinp_right_semi_comments,
|wrk: Workdir, mut cmd: process::Command| {
cmd.arg("--right-semi");
let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
let expected = vec![
svec!["city", "place"],
svec!["Boston", "Logan Airport"],
svec!["Boston", "Boston Garden"],
svec!["Buffalo", "Ralph Wilson Stadium"],
];
assert_eq!(got, expected);
}
);

joinp_test!(
joinp_right_anti,
|wrk: Workdir, mut cmd: process::Command| {
cmd.arg("--right-anti");
let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
let expected = vec![svec!["city", "place"], svec!["Orlando", "Disney World"]];
assert_eq!(got, expected);
}
);

joinp_test_tab!(
joinp_right_anti_tab,
|wrk: Workdir, mut cmd: process::Command| {
cmd.arg("--right-anti");
let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
let expected = vec![svec!["city", "place"], svec!["Orlando", "Disney World"]];
assert_eq!(got, expected);
}
);

joinp_test_comments!(
joinp_right_anti_comments,
|wrk: Workdir, mut cmd: process::Command| {
cmd.arg("--right-anti");
let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
let expected = vec![svec!["city", "place"], svec!["Orlando", "Disney World"]];
assert_eq!(got, expected);
}
);

0 comments on commit 6e3532d

Please sign in to comment.