1111_IDENTIFIER = re .compile (r"[^a-zA-Z0-9_]+" )
1212
1313
14- def catalog (metadata : MetaData ) -> tuple [Table , Table ]:
14+ def catalog (metadata : MetaData ) -> tuple [Table , Table , Table ]:
1515 datasets = Table (
1616 "dataset_catalog" , metadata ,
1717 Column ("dataset_id" , String (255 ), primary_key = True ),
@@ -46,8 +46,13 @@ def catalog(metadata: MetaData) -> tuple[Table, Table]:
4646 Column ("value_labels" , Text , nullable = False , default = "{}" ),
4747 Column ("missing_ranges" , Text , nullable = False , default = "[]" ),
4848 )
49- return datasets , variables
50-
49+ fidelity_events = Table (
50+ "fidelity_event_catalog" , metadata ,
51+ Column ("dataset_id" , String (255 ), primary_key = True ),
52+ Column ("code" , String (128 ), primary_key = True ),
53+ Column ("detail" , Text , nullable = False ),
54+ )
55+ return datasets , variables , fidelity_events
5156
5257
5358def multiple_response_set_catalog (metadata : MetaData ) -> Table :
@@ -103,12 +108,13 @@ def create_wide_dataset(
103108 source_created_at : str | None = None , source_modified_at : str | None = None ,
104109 imported_at : str = "" ,
105110 multiple_response_sets : str = "{}" ,
111+ fidelity_events : Iterable [Mapping [str , str ]] = (),
106112) -> dict [str , Any ]:
107113 profile = validate_connection_url (database_url )
108114 preflight (profile , len (variables ))
109115 engine = create_engine (database_url )
110116 metadata = MetaData ()
111- datasets , variable_catalog = catalog (metadata )
117+ datasets , variable_catalog , fidelity_event_catalog = catalog (metadata )
112118 multiple_response_catalog = multiple_response_set_catalog (metadata )
113119 data_table = Table (
114120 data_table_name (dataset_id ), metadata ,
@@ -117,7 +123,7 @@ def create_wide_dataset(
117123 nullable = item ["storage_kind" ] == "numeric" ) for item in variables ),
118124 )
119125 with engine .begin () as connection :
120- metadata .create_all (connection , tables = [datasets , variable_catalog , multiple_response_catalog ])
126+ metadata .create_all (connection , tables = [datasets , variable_catalog , multiple_response_catalog , fidelity_event_catalog ])
121127 if connection .execute (select (datasets .c .dataset_id ).where (datasets .c .dataset_id == dataset_id )).first ():
122128 raise ValueError (f"Dataset { dataset_id !r} already exists; imports never overwrite a dataset." )
123129 if connection .execute (select (datasets .c .dataset_id ).where (datasets .c .data_table == data_table .name )).first ():
@@ -138,12 +144,19 @@ def create_wide_dataset(
138144 mrset_rows = multiple_response_set_rows (dataset_id , multiple_response_sets )
139145 if mrset_rows :
140146 connection .execute (insert (multiple_response_catalog ), mrset_rows )
147+ event_rows = [
148+ {"dataset_id" : dataset_id , "code" : event ["code" ], "detail" : event ["detail" ]}
149+ for event in fidelity_events
150+ ]
151+ if event_rows :
152+ connection .execute (insert (fidelity_event_catalog ), event_rows )
141153 if materialized :
142154 try :
143155 connection .execute (insert (data_table ), materialized )
144156 except Exception :
145157 data_table .drop (connection , checkfirst = True )
146158 connection .execute (delete (multiple_response_catalog ).where (multiple_response_catalog .c .dataset_id == dataset_id ))
159+ connection .execute (delete (fidelity_event_catalog ).where (fidelity_event_catalog .c .dataset_id == dataset_id ))
147160 connection .execute (delete (variable_catalog ).where (variable_catalog .c .dataset_id == dataset_id ))
148161 connection .execute (delete (datasets ).where (datasets .c .dataset_id == dataset_id ))
149162 connection .commit ()
@@ -154,7 +167,7 @@ def create_wide_dataset(
154167def read_wide_dataset (* , database_url : str , dataset_id : str ) -> tuple [dict [str , Any ], list [dict [str , Any ]], list [dict [str , Any ]]]:
155168 engine = create_engine (database_url )
156169 metadata = MetaData ()
157- datasets , variable_catalog = catalog (metadata )
170+ datasets , variable_catalog , _ = catalog (metadata )
158171 with engine .connect () as connection :
159172 dataset = connection .execute (select (datasets ).where (datasets .c .dataset_id == dataset_id )).mappings ().one ()
160173 data_table = Table (dataset ["data_table" ], MetaData (), autoload_with = connection )
@@ -165,6 +178,21 @@ def read_wide_dataset(*, database_url: str, dataset_id: str) -> tuple[dict[str,
165178 return dict (dataset ), [dict (item ) for item in variables ], [dict (item ) for item in rows ]
166179
167180
181+ def read_fidelity_events (* , database_url : str , dataset_id : str ) -> tuple [dict [str , str ], ...]:
182+ """Read import-time fidelity diagnostics for a catalogued dataset."""
183+ engine = create_engine (database_url )
184+ metadata = MetaData ()
185+ _ , _ , fidelity_event_catalog = catalog (metadata )
186+ with engine .connect () as connection :
187+ fidelity_event_catalog .create (connection , checkfirst = True )
188+ events = connection .execute (
189+ select (fidelity_event_catalog )
190+ .where (fidelity_event_catalog .c .dataset_id == dataset_id )
191+ .order_by (fidelity_event_catalog .c .code )
192+ ).mappings ().all ()
193+ return tuple ({"code" : item ["code" ], "detail" : item ["detail" ]} for item in events )
194+
195+
168196def validate_wide_dataset (* , database_url : str , dataset_id : str ) -> dict [str , Any ]:
169197 dataset , variables , rows = read_wide_dataset (database_url = database_url , dataset_id = dataset_id )
170198 profile = validate_connection_url (database_url )
0 commit comments