mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
join: add support for full outer joins
This commit is contained in:
parent
01be7b356f
commit
1bb0237281
6 changed files with 65 additions and 12 deletions
|
@ -19,7 +19,6 @@ static NAME: &str = "join";
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
enum FileNum {
|
enum FileNum {
|
||||||
None,
|
|
||||||
File1,
|
File1,
|
||||||
File2,
|
File2,
|
||||||
}
|
}
|
||||||
|
@ -41,7 +40,8 @@ enum CheckOrder {
|
||||||
struct Settings {
|
struct Settings {
|
||||||
key1: usize,
|
key1: usize,
|
||||||
key2: usize,
|
key2: usize,
|
||||||
print_unpaired: FileNum,
|
print_unpaired1: bool,
|
||||||
|
print_unpaired2: bool,
|
||||||
print_joined: bool,
|
print_joined: bool,
|
||||||
ignore_case: bool,
|
ignore_case: bool,
|
||||||
separator: Sep,
|
separator: Sep,
|
||||||
|
@ -57,7 +57,8 @@ impl Default for Settings {
|
||||||
Settings {
|
Settings {
|
||||||
key1: 0,
|
key1: 0,
|
||||||
key2: 0,
|
key2: 0,
|
||||||
print_unpaired: FileNum::None,
|
print_unpaired1: false,
|
||||||
|
print_unpaired2: false,
|
||||||
print_joined: true,
|
print_joined: true,
|
||||||
ignore_case: false,
|
ignore_case: false,
|
||||||
separator: Sep::Whitespaces,
|
separator: Sep::Whitespaces,
|
||||||
|
@ -243,7 +244,7 @@ impl<'a> State<'a> {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
stdin: &'a Stdin,
|
stdin: &'a Stdin,
|
||||||
key: usize,
|
key: usize,
|
||||||
print_unpaired: FileNum,
|
print_unpaired: bool,
|
||||||
) -> State<'a> {
|
) -> State<'a> {
|
||||||
let f = if name == "-" {
|
let f = if name == "-" {
|
||||||
Box::new(stdin.lock()) as Box<dyn BufRead>
|
Box::new(stdin.lock()) as Box<dyn BufRead>
|
||||||
|
@ -258,7 +259,7 @@ impl<'a> State<'a> {
|
||||||
key,
|
key,
|
||||||
file_name: name,
|
file_name: name,
|
||||||
file_num,
|
file_num,
|
||||||
print_unpaired: print_unpaired == file_num,
|
print_unpaired,
|
||||||
lines: f.lines(),
|
lines: f.lines(),
|
||||||
seq: Vec::new(),
|
seq: Vec::new(),
|
||||||
max_fields: None,
|
max_fields: None,
|
||||||
|
@ -450,11 +451,19 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
|
|
||||||
let mut settings: Settings = Default::default();
|
let mut settings: Settings = Default::default();
|
||||||
|
|
||||||
if let Some(value) = matches.value_of("v") {
|
let v_values = matches.values_of("v");
|
||||||
settings.print_unpaired = parse_file_number(value);
|
if v_values.is_some() {
|
||||||
settings.print_joined = false;
|
settings.print_joined = false;
|
||||||
} else if let Some(value) = matches.value_of("a") {
|
}
|
||||||
settings.print_unpaired = parse_file_number(value);
|
|
||||||
|
let unpaired = v_values
|
||||||
|
.unwrap_or_default()
|
||||||
|
.chain(matches.values_of("a").unwrap_or_default());
|
||||||
|
for file_num in unpaired {
|
||||||
|
match parse_file_number(file_num) {
|
||||||
|
FileNum::File1 => settings.print_unpaired1 = true,
|
||||||
|
FileNum::File2 => settings.print_unpaired2 = true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ignore_case = matches.is_present("i");
|
settings.ignore_case = matches.is_present("i");
|
||||||
|
@ -520,7 +529,8 @@ When FILE1 or FILE2 (not both) is -, read standard input.",
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("a")
|
Arg::with_name("a")
|
||||||
.short("a")
|
.short("a")
|
||||||
.takes_value(true)
|
.multiple(true)
|
||||||
|
.number_of_values(1)
|
||||||
.possible_values(&["1", "2"])
|
.possible_values(&["1", "2"])
|
||||||
.value_name("FILENUM")
|
.value_name("FILENUM")
|
||||||
.help(
|
.help(
|
||||||
|
@ -531,6 +541,9 @@ FILENUM is 1 or 2, corresponding to FILE1 or FILE2",
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("v")
|
Arg::with_name("v")
|
||||||
.short("v")
|
.short("v")
|
||||||
|
.multiple(true)
|
||||||
|
.number_of_values(1)
|
||||||
|
.possible_values(&["1", "2"])
|
||||||
.value_name("FILENUM")
|
.value_name("FILENUM")
|
||||||
.help("like -a FILENUM, but suppress joined output lines"),
|
.help("like -a FILENUM, but suppress joined output lines"),
|
||||||
)
|
)
|
||||||
|
@ -617,7 +630,7 @@ fn exec(file1: &str, file2: &str, settings: &Settings) -> i32 {
|
||||||
file1,
|
file1,
|
||||||
&stdin,
|
&stdin,
|
||||||
settings.key1,
|
settings.key1,
|
||||||
settings.print_unpaired,
|
settings.print_unpaired1,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut state2 = State::new(
|
let mut state2 = State::new(
|
||||||
|
@ -625,7 +638,7 @@ fn exec(file1: &str, file2: &str, settings: &Settings) -> i32 {
|
||||||
file2,
|
file2,
|
||||||
&stdin,
|
&stdin,
|
||||||
settings.key2,
|
settings.key2,
|
||||||
settings.print_unpaired,
|
settings.print_unpaired2,
|
||||||
);
|
);
|
||||||
|
|
||||||
let input = Input::new(
|
let input = Input::new(
|
||||||
|
|
|
@ -94,6 +94,18 @@ fn unpaired_lines() {
|
||||||
.arg("2")
|
.arg("2")
|
||||||
.succeeds()
|
.succeeds()
|
||||||
.stdout_only_fixture("unpaired_lines.expected");
|
.stdout_only_fixture("unpaired_lines.expected");
|
||||||
|
|
||||||
|
new_ucmd!()
|
||||||
|
.arg("fields_3.txt")
|
||||||
|
.arg("fields_2.txt")
|
||||||
|
.arg("-1")
|
||||||
|
.arg("2")
|
||||||
|
.arg("-a")
|
||||||
|
.arg("1")
|
||||||
|
.arg("-a")
|
||||||
|
.arg("2")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only_fixture("unpaired_lines_outer.expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -107,6 +119,18 @@ fn suppress_joined() {
|
||||||
.arg("2")
|
.arg("2")
|
||||||
.succeeds()
|
.succeeds()
|
||||||
.stdout_only_fixture("suppress_joined.expected");
|
.stdout_only_fixture("suppress_joined.expected");
|
||||||
|
|
||||||
|
new_ucmd!()
|
||||||
|
.arg("fields_3.txt")
|
||||||
|
.arg("fields_2.txt")
|
||||||
|
.arg("-1")
|
||||||
|
.arg("2")
|
||||||
|
.arg("-a")
|
||||||
|
.arg("1")
|
||||||
|
.arg("-v")
|
||||||
|
.arg("2")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only_fixture("suppress_joined_outer.expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
1
tests/fixtures/join/fields_3.txt
vendored
1
tests/fixtures/join/fields_3.txt
vendored
|
@ -4,3 +4,4 @@ c 4 h
|
||||||
f 5 i
|
f 5 i
|
||||||
g 6 j
|
g 6 j
|
||||||
h 7 k
|
h 7 k
|
||||||
|
i 99 l
|
||||||
|
|
4
tests/fixtures/join/suppress_joined_outer.expected
vendored
Normal file
4
tests/fixtures/join/suppress_joined_outer.expected
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
1 a
|
||||||
|
8 h
|
||||||
|
9 i
|
||||||
|
99 i l
|
|
@ -4,3 +4,4 @@
|
||||||
i 5 f
|
i 5 f
|
||||||
j 6 g
|
j 6 g
|
||||||
k 7 h
|
k 7 h
|
||||||
|
l 99 i
|
||||||
|
|
10
tests/fixtures/join/unpaired_lines_outer.expected
vendored
Normal file
10
tests/fixtures/join/unpaired_lines_outer.expected
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
1 a
|
||||||
|
2 a f b
|
||||||
|
3 b g c
|
||||||
|
4 c h d
|
||||||
|
5 f i e
|
||||||
|
6 g j f
|
||||||
|
7 h k g
|
||||||
|
8 h
|
||||||
|
9 i
|
||||||
|
99 i l
|
Loading…
Add table
Add a link
Reference in a new issue