@@ -108,7 +108,9 @@ def run_query(query_file: Path, endpoint: str) -> dict[str, Any]:
108108 return json .loads (result .stdout )
109109
110110
111- def extract_rows (data : dict [str , Any ], include_harvest_date : bool = False ) -> list [tuple ]:
111+ def extract_rows (
112+ data : dict [str , Any ], include_harvest_date : bool = False , include_found_in_registry : bool = False
113+ ) -> list [tuple ]:
112114 """Extract result rows from an OpenSearch query response."""
113115 rows = []
114116 for hit in data .get ("hits" , {}).get ("hits" , []):
@@ -135,16 +137,23 @@ def extract_rows(data: dict[str, Any], include_harvest_date: bool = False) -> li
135137 if isinstance (harvest_date , list ):
136138 harvest_date = harvest_date [0 ] if harvest_date else ""
137139 rows .append ((node , lidvid , product_class , harvest_date ))
140+ elif include_found_in_registry :
141+ found = source .get ("found_in_registry" , "" )
142+ if isinstance (found , list ):
143+ found = found [0 ] if found else ""
144+ rows .append ((node , lidvid , product_class , str (found ).lower ()))
138145 else :
139146 rows .append ((node , lidvid , product_class ))
140147
141148 return rows
142149
143150
144- def write_rows_to_csv (rows : list [tuple ], output_file : Path ) -> int :
151+ def write_rows_to_csv (rows : list [tuple ], output_file : Path , header : tuple | None = None ) -> int :
145152 """Write rows to a CSV file. Returns the number of rows written."""
146153 with open (output_file , "w" , newline = "" ) as csvfile :
147154 writer = csv .writer (csvfile )
155+ if header :
156+ writer .writerow (header )
148157 for row in rows :
149158 writer .writerow (row )
150159 return len (rows )
@@ -157,9 +166,13 @@ def annotate_version_status(rows: list[tuple]) -> list[tuple]:
157166 ``urn:nasa:pds:<lid>::<major>.<minor>``. Version comparison is numeric so
158167 that e.g. ``3.9 < 3.13``.
159168
169+ Rows must include ``found_in_registry`` as the fourth element (index 3).
170+ The highest-versioned LIDVID across *all* rows (missing or not) for each LID
171+ determines the superseded flag. A row is superseded if a higher version
172+ exists anywhere in the full set.
173+
160174 Returns a new list of rows with an additional ``superseded`` column appended
161- (string ``"true"`` or ``"false"``). The highest-versioned row per LID gets
162- ``"false"``; all others get ``"true"``.
175+ (string ``"true"`` or ``"false"``).
163176 """
164177 by_lid : dict [str , list [tuple [tuple [int , ...], int ]]] = defaultdict (list )
165178
@@ -186,6 +199,21 @@ def annotate_version_status(rows: list[tuple]) -> list[tuple]:
186199 return [row + ("true" if idx in superseded_indices else "false" ,) for idx , row in enumerate (rows )]
187200
188201
202+ def filter_missing_rows (rows : list [tuple ]) -> list [tuple ]:
203+ """Filter rows to only those where found_in_registry is false.
204+
205+ Expects rows in the form (node, lidvid, product_class, found_in_registry, superseded).
206+ Returns rows with the found_in_registry column removed, preserving the superseded column.
207+ """
208+ result = []
209+ for row in rows :
210+ # found_in_registry is at index 3; superseded is at index 4
211+ found = str (row [3 ]).lower ()
212+ if found != "true" :
213+ result .append (row [:3 ] + row [4 :])
214+ return result
215+
216+
189217def _count_by_node (csv_path : Path , superseded : bool | None = None ) -> dict [str , int ]:
190218 """Return a node→count mapping from a CSV file (node is the first column).
191219
@@ -198,7 +226,7 @@ def _count_by_node(csv_path: Path, superseded: bool | None = None) -> dict[str,
198226 if csv_path .exists ():
199227 with open (csv_path , "r" ) as f :
200228 for row in csv .reader (f ):
201- if not row :
229+ if not row or row [ 0 ] == "node" :
202230 continue
203231 if superseded is not None :
204232 if len (row ) < 4 :
@@ -535,13 +563,20 @@ def main() -> int:
535563 try :
536564 print_info (f"Querying for { description } ..." )
537565 data = run_query (query_file , endpoint )
538- rows = extract_rows (data , include_harvest_date )
566+ rows = extract_rows (data , include_harvest_date , include_found_in_registry = split_versions )
539567
540568 if split_versions :
541- # Annotate each row with a superseded column before writing
569+ # Annotate using all returned rows (including found_in_registry=true) so that
570+ # version ordering is determined across the full set, then filter to missing only.
542571 rows = annotate_version_status (rows )
543-
544- count = write_rows_to_csv (rows , output_file )
572+ rows = filter_missing_rows (rows )
573+ header = ("node" , "lidvid" , "product_class" , "superseded" )
574+ elif include_harvest_date :
575+ header = ("node" , "lidvid" , "product_class" , "harvest_date" )
576+ else :
577+ header = ("node" , "lidvid" , "product_class" )
578+
579+ count = write_rows_to_csv (rows , output_file , header = header )
545580 print_info (f" → { output_file .name } ({ count } records)" )
546581 output_files .append (output_file )
547582
0 commit comments