Repository: dathere/qsv (language: rust)

Issue:
qsv search --flag, row index starts from 2

### Discussed in https://github.com/dathere/qsv/discussions/2502

<div type='discussions-op-text'>

<sup>Originally posted by **caeu** February  5, 2025</sup>
When using 
qsv search --flag hits 'first_row' 
assuming this hits something in the first row.

The new adedd column 'hits' starts counting from 2 if matches the first row.

This happens even when combined with --no-headers

qsv defaults and choices are so good. The choice here looks odd to me.
I suspect it is an oversight.</div>


Discussion / hints:

Fix patch:
diff --git a/src/cmd/search.rs b/src/cmd/search.rs
index abc8f46e8..3d4a24ab3 100644
--- a/src/cmd/search.rs
+++ b/src/cmd/search.rs
@@ -193,7 +193,7 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
     }
 
     let mut record = csv::ByteRecord::new();
-    let mut flag_rowi: u64 = 1;
+    let mut flag_rowi: u64 = 0;
     let mut match_ctr: u64 = 0;
     let mut row_ctr: u64 = 0;
     let mut m;
diff --git a/src/cmd/searchset.rs b/src/cmd/searchset.rs
index 0adb3cde0..7696b9a6c 100644
--- a/src/cmd/searchset.rs
+++ b/src/cmd/searchset.rs
@@ -220,7 +220,7 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
     }
 
     let mut record = csv::ByteRecord::new();
-    let mut flag_rowi: u64 = 1;
+    let mut flag_rowi: u64 = 0;
     let mut match_row_ctr: u64 = 0;
     let mut total_matches: u64 = 0;
     let mut row_ctr: u64 = 0;


Test patch:
diff --git a/resources/test/boston311-100-pii-searchset.csv b/resources/test/boston311-100-pii-searchset.csv
index d50f33e77..b66c960b0 100644
--- a/resources/test/boston311-100-pii-searchset.csv
+++ b/resources/test/boston311-100-pii-searchset.csv
@@ -1,6 +1,6 @@
 case_enquiry_id,open_dt,target_dt,closed_dt,ontime,case_status,closure_reason,case_title,subject,reason,type,queue,department,submittedphoto,closedphoto,location,fire_district,pwd_district,city_council_district,police_district,neighborhood,neighborhood_services_district,ward,precinct,location_street_name,location_zipcode,latitude,longitude,source,flagged
-101004113403,2022-01-01 09:43:36,2022-01-31 09:43:36,2022-01-03 10:06:33,ONTIME,Closed,Case Closed. Closed date : 2022-01-03 10:06:33.717 Case Noted area inspector has been monitoring the area. call 212-555-1234 ,Rodent Activity,Inspectional Services,Environmental Services,Rodent Activity,ISD_Environmental Services (INTERNAL),ISD,https://311.boston.gov/media/boston/report/photos/61d0688a05bbcf180c297be9/report.jpg,,18 Durham St  Boston  MA  02115,4,1C,7,D4,Back Bay,14,Ward 4,0405,18 Durham St,02115,42.3439,-71.0806,Citizens Connect App,18;Phone
-101004113431,2022-01-01 10:35:45,2022-01-05 08:30:00,2022-01-01 14:59:41,ONTIME,Closed,Case Closed. Closed date : Sat Jan 01 14:59:41 EST 2022 Noted Bags sent in for collection. Ticket issued and collected SSN - 987-65-4320 ,Improper Storage of Trash (Barrels),Public Works Department,Code Enforcement,Improper Storage of Trash (Barrels),PWDx_Code Enforcement,PWDx,https://311.boston.gov/media/boston/report/photos/61d074c005bbcf180c298048/report.jpg,,40 Anderson St  Boston  MA  02114,3,1B,8,A1,Beacon Hill,14,Ward 5,0504,40 Anderson St,02114,42.3598,-71.0676,Citizens Connect App,20;SSN
-101004113717,2022-01-01 21:11:00,2022-01-04 08:30:00,2022-01-04 09:30:03,OVERDUE,Closed,Case Closed. Closed date : 2022-01-04 09:30:03.91 Case Noted Dear Constituent     NGRID is aware of the broken gate and will send a crew to repair.    We are waiting on there schedule to do so.    Regards   Rich DiMarzo  781-853-9016 ,Request for Pothole Repair,Public Works Department,Highway Maintenance,Request for Pothole Repair,PWDx_Contractor Complaints,PWDx,https://311.boston.gov/media/boston/report/photos/61d109cf05bbcf180c29c167/Pothole_1.jpg,,INTERSECTION of Charles River Plz & Cambridge St  Boston  MA  ,3,1B,7,A1,Beacon Hill,3,3,0305,INTERSECTION Charles River Plz & Cambridge St,,42.3594,-71.0587,Citizens Connect App,23;Phone
-101004113729,2022-01-01 21:54:56,2022-01-04 08:30:00,2022-01-02 23:54:13,ONTIME,Closed,Case Closed. Closed date : 2022-01-02 23:54:13.31 Case Resolved BOSTON POLICE WERE THERE TO TICKET. Person paid with Amex - 378734493671000,Parking Enforcement,Transportation - Traffic Division,Enforcement & Abandoned Vehicles,Parking Enforcement,BTDT_Parking Enforcement,BTDT,https://311.boston.gov/media/boston/report/photos/61d1115205bbcf180c29c32f/report.jpg,,INTERSECTION of Verdun St & Gallivan Blvd  Dorchester  MA  ,8,07,3,C11,Dorchester,7,16,1611,INTERSECTION Verdun St & Gallivan Blvd,,42.3594,-71.0587,Citizens Connect App,25;American Express
-101004114033,2022-01-02 13:38:41,2022-01-05 08:30:00,2022-01-03 07:08:35,ONTIME,Closed,Case Closed. Closed date : Mon Jan 03 07:08:35 EST 2022 Resolved No violation found at this time  today is trash day. Please send an email to joeblows@aol.com or call him at 212-123-5432 ,Improper Storage of Trash (Barrels),Public Works Department,Code Enforcement,Improper Storage of Trash (Barrels),PWDx_Code Enforcement,PWDx,https://311.boston.gov/media/boston/report/photos/61d1f12405bbcf180c2a3082/report.jpg,,INTERSECTION of Lewis St & North St  Boston  MA  ,3,1B,1,A1,Downtown / Financial District,3,3,,INTERSECTION Lewis St & North St,,42.3594,-71.0587,Citizens Connect App,"48;Email,Phone"
+101004113403,2022-01-01 09:43:36,2022-01-31 09:43:36,2022-01-03 10:06:33,ONTIME,Closed,Case Closed. Closed date : 2022-01-03 10:06:33.717 Case Noted area inspector has been monitoring the area. call 212-555-1234 ,Rodent Activity,Inspectional Services,Environmental Services,Rodent Activity,ISD_Environmental Services (INTERNAL),ISD,https://311.boston.gov/media/boston/report/photos/61d0688a05bbcf180c297be9/report.jpg,,18 Durham St  Boston  MA  02115,4,1C,7,D4,Back Bay,14,Ward 4,0405,18 Durham St,02115,42.3439,-71.0806,Citizens Connect App,17;Phone
+101004113431,2022-01-01 10:35:45,2022-01-05 08:30:00,2022-01-01 14:59:41,ONTIME,Closed,Case Closed. Closed date : Sat Jan 01 14:59:41 EST 2022 Noted Bags sent in for collection. Ticket issued and collected SSN - 987-65-4320 ,Improper Storage of Trash (Barrels),Public Works Department,Code Enforcement,Improper Storage of Trash (Barrels),PWDx_Code Enforcement,PWDx,https://311.boston.gov/media/boston/report/photos/61d074c005bbcf180c298048/report.jpg,,40 Anderson St  Boston  MA  02114,3,1B,8,A1,Beacon Hill,14,Ward 5,0504,40 Anderson St,02114,42.3598,-71.0676,Citizens Connect App,19;SSN
+101004113717,2022-01-01 21:11:00,2022-01-04 08:30:00,2022-01-04 09:30:03,OVERDUE,Closed,Case Closed. Closed date : 2022-01-04 09:30:03.91 Case Noted Dear Constituent     NGRID is aware of the broken gate and will send a crew to repair.    We are waiting on there schedule to do so.    Regards   Rich DiMarzo  781-853-9016 ,Request for Pothole Repair,Public Works Department,Highway Maintenance,Request for Pothole Repair,PWDx_Contractor Complaints,PWDx,https://311.boston.gov/media/boston/report/photos/61d109cf05bbcf180c29c167/Pothole_1.jpg,,INTERSECTION of Charles River Plz & Cambridge St  Boston  MA  ,3,1B,7,A1,Beacon Hill,3,3,0305,INTERSECTION Charles River Plz & Cambridge St,,42.3594,-71.0587,Citizens Connect App,22;Phone
+101004113729,2022-01-01 21:54:56,2022-01-04 08:30:00,2022-01-02 23:54:13,ONTIME,Closed,Case Closed. Closed date : 2022-01-02 23:54:13.31 Case Resolved BOSTON POLICE WERE THERE TO TICKET. Person paid with Amex - 378734493671000,Parking Enforcement,Transportation - Traffic Division,Enforcement & Abandoned Vehicles,Parking Enforcement,BTDT_Parking Enforcement,BTDT,https://311.boston.gov/media/boston/report/photos/61d1115205bbcf180c29c32f/report.jpg,,INTERSECTION of Verdun St & Gallivan Blvd  Dorchester  MA  ,8,07,3,C11,Dorchester,7,16,1611,INTERSECTION Verdun St & Gallivan Blvd,,42.3594,-71.0587,Citizens Connect App,24;American Express
+101004114033,2022-01-02 13:38:41,2022-01-05 08:30:00,2022-01-03 07:08:35,ONTIME,Closed,Case Closed. Closed date : Mon Jan 03 07:08:35 EST 2022 Resolved No violation found at this time  today is trash day. Please send an email to joeblows@aol.com or call him at 212-123-5432 ,Improper Storage of Trash (Barrels),Public Works Department,Code Enforcement,Improper Storage of Trash (Barrels),PWDx_Code Enforcement,PWDx,https://311.boston.gov/media/boston/report/photos/61d1f12405bbcf180c2a3082/report.jpg,,INTERSECTION of Lewis St & North St  Boston  MA  ,3,1B,1,A1,Downtown / Financial District,3,3,,INTERSECTION Lewis St & North St,,42.3594,-71.0587,Citizens Connect App,"47;Email,Phone"
diff --git a/tests/test_search.rs b/tests/test_search.rs
index 15a40c7fe..4915b9f6f 100644
--- a/tests/test_search.rs
+++ b/tests/test_search.rs
@@ -67,7 +67,7 @@ fn search_matchonly_json() {
         .args(["--flag", "M"]);
 
     let got: String = wrk.stdout(&mut cmd);
-    let expected = r#"[{"M":"2"},{"M":"4"}]"#;
+    let expected = r#"[{"M":"1"},{"M":"3"}]"#;
     assert_eq!(got, expected);
     wrk.assert_success(&mut cmd);
 }
@@ -472,13 +472,14 @@ fn search_invert_match_no_headers_count() {
 #[test]
 fn search_flag() {
     let wrk = Workdir::new("search_flag");
-    wrk.create("data.csv", data(false));
+    wrk.create("data.csv", data(true));
     let mut cmd = wrk.command("search");
     cmd.arg("^foo").arg("data.csv").args(["--flag", "flagged"]);
 
     let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
     let expected = vec![
-        svec!["foobar", "barfoo", "flagged"],
+        svec!["h1", "h2", "flagged"],
+        svec!["foobar", "barfoo", "1"],
         svec!["a", "b", "0"],
         svec!["barfoo", "foobar", "3"],
         svec!["Ḟooƀar", "ḃarḟoo", "0"],
@@ -490,12 +491,12 @@ fn search_flag() {
 #[test]
 fn search_flag_match_only() {
     let wrk = Workdir::new("search_flag_match_only");
-    wrk.create("data.csv", data(false));
+    wrk.create("data.csv", data(true));
     let mut cmd = wrk.command("search");
     cmd.arg("^foo").arg("data.csv").args(["--flag", "M"]);
 
     let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
-    let expected = vec![svec!["M"], svec!["3"]];
+    let expected = vec![svec!["M"], svec!["1"], svec!["3"]];
     assert_eq!(got, expected);
     wrk.assert_success(&mut cmd);
 }
@@ -503,14 +504,15 @@ fn search_flag_match_only() {
 #[test]
 fn search_flag_invert_match() {
     let wrk = Workdir::new("search_flag");
-    wrk.create("data.csv", data(false));
+    wrk.create("data.csv", data(true));
     let mut cmd = wrk.command("search");
     cmd.arg("^foo").arg("data.csv").args(["--flag", "flagged"]);
     cmd.arg("--invert-match");
 
     let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
     let expected = vec![
-        svec!["foobar", "barfoo", "flagged"],
+        svec!["h1", "h2", "flagged"],
+        svec!["foobar", "barfoo", "0"],
         svec!["a", "b", "2"],
         svec!["barfoo", "foobar", "0"],
         svec!["Ḟooƀar", "ḃarḟoo", "4"],
@@ -523,7 +525,7 @@ fn search_flag_invert_match() {
 #[test]
 fn search_flag_invert_match_matchonly() {
     let wrk = Workdir::new("search_flag_invert_match_matchonly");
-    wrk.create("data.csv", data(false));
+    wrk.create("data.csv", data(true));
     let mut cmd = wrk.command("search");
     cmd.arg("^foo").arg("data.csv").args(["--flag", "M"]);
     cmd.arg("--invert-match");
@@ -538,7 +540,7 @@ fn search_flag_invert_match_matchonly() {
 #[test]
 fn search_flag_invert_match_count() {
     let wrk = Workdir::new("search_flag");
-    wrk.create("data.csv", data(false));
+    wrk.create("data.csv", data(true));
     let mut cmd = wrk.command("search");
     cmd.arg("^foo")
         .arg("--count")
@@ -548,7 +550,8 @@ fn search_flag_invert_match_count() {
 
     let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
     let expected = vec![
-        svec!["foobar", "barfoo", "flagged"],
+        svec!["h1", "h2", "flagged"],
+        svec!["foobar", "barfoo", "0"],
         svec!["a", "b", "2"],
         svec!["barfoo", "foobar", "0"],
         svec!["Ḟooƀar", "ḃarḟoo", "4"],
@@ -564,7 +567,7 @@ fn search_flag_invert_match_count() {
 #[test]
 fn search_flag_invert_matchonly_count() {
     let wrk = Workdir::new("search_flag_invert_matchonly_count");
-    wrk.create("data.csv", data(false));
+    wrk.create("data.csv", data(true));
     let mut cmd = wrk.command("search");
     cmd.arg("^foo")
         .arg("--count")
diff --git a/tests/test_searchset.rs b/tests/test_searchset.rs
index 35184b715..2d0d59be2 100644
--- a/tests/test_searchset.rs
+++ b/tests/test_searchset.rs
@@ -349,7 +349,7 @@ fn searchset_invert_match_no_headers() {
 #[test]
 fn searchset_flag() {
     let wrk = Workdir::new("searchset_flag");
-    wrk.create("data.csv", data(false));
+    wrk.create("data.csv", data(true));
     wrk.create("regexset.txt", regexset_file());
     let mut cmd = wrk.command("searchset");
     cmd.arg("regexset.txt")
@@ -358,7 +358,8 @@ fn searchset_flag() {
 
     let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
     let expected = vec![
-        svec!["foobar", "barfoo", "flagged"],
+        svec!["h1", "h2", "flagged"],
+        svec!["foobar", "barfoo", "1;1,2"],
         svec!["a", "b", "0"],
         svec!["barfoo", "foobar", "3;1,2"],
         svec!["is waldo here", "spot", "4;3"],
@@ -373,7 +374,7 @@ fn searchset_flag() {
 fn searchset_flag_invert_match() {
     let wrk = Workdir::new("searchset_flag");
     wrk.create("regexset.txt", regexset_file());
-    wrk.create("data.csv", data(false));
+    wrk.create("data.csv", data(true));
     let mut cmd = wrk.command("searchset");
     cmd.arg("regexset.txt")
         .arg("data.csv")
@@ -382,7 +383,8 @@ fn searchset_flag_invert_match() {
 
     let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
     let expected = vec![
-        svec!["foobar", "barfoo", "flagged"],
+        svec!["h1", "h2", "flagged"],
+        svec!["foobar", "barfoo", "0"],
         svec!["a", "b", "2"],
         svec!["barfoo", "foobar", "0"],
         svec!["is waldo here", "spot", "0"],