@@ -88,6 +88,10 @@ def get_table_names(self):
8888 cursor .close ()
8989 return tables
9090
91+ def get_column_values (self , columns : list [str ], from_table : str ):
92+ cursor = self .conn .execute (f"SELECT { ', ' .join (columns )} FROM { from_table } " )
93+ return cursor .fetchall ()
94+
9195 @property
9296 def get_db_full_info (self ):
9397 """
@@ -100,27 +104,25 @@ def get_db_full_info(self):
100104 db_tables_info = {}
101105 table_names = self .get_table_names ()
102106 for table_name in table_names :
103- row_count = self .count_all_entries_in_table (table_name )
107+ row_count = self .count_all_entries (table_name )
104108 db_tables_info .update (
105109 {
106110 table_name : row_count ,
107111 }
108112 )
109113 return db_tables_info
110114
111- def count_all_entries_in_table (self , table : str ) -> int :
112- count = self .conn .execute (f"SELECT COUNT(*) FROM { table } " ).fetchone ()[0 ]
115+ def count_all_entries (self , from_table : str ) -> int :
116+ count = self .conn .execute (f"SELECT COUNT(*) FROM { from_table } " ).fetchone ()[0 ]
113117 return count
114118
115- def count_notnull_entries_in_table (
116- self , column : str , table : str
119+ def count_notnull_entries (
120+ self , columns : list [ str ], from_table : str
117121 ) -> Union [int , None ]:
118- if self .has_column (column , table ):
119- count = self .conn .execute (
120- f"SELECT COUNT(*) FROM { table } WHERE { column } IS NOT NULL"
121- ).fetchone ()[0 ]
122- return count
123- return None
122+ count = self .conn .execute (
123+ f"SELECT COUNT(*) FROM { from_table } WHERE { ', ' .join (columns )} IS NOT NULL"
124+ ).fetchone ()[0 ]
125+ return count
124126
125127 def has_column (self , column_name : str , table_name : str ) -> bool :
126128 """
@@ -134,3 +136,163 @@ def has_column(self, column_name: str, table_name: str) -> bool:
134136 columns = [row [1 ] for row in cursor .fetchall ()] # row[1] is the column name
135137 cursor .close ()
136138 return column_name in columns
139+
140+ def get_null_entries (self , from_table : str ) -> list :
141+ cursor = self .conn .execute (
142+ f"SELECT id, summary FROM { from_table } WHERE embedding IS NULL"
143+ )
144+ return cursor .fetchall ()
145+
146+ def get_distances (self ) -> list [tuple [int , int , float ]]:
147+ """
148+ Returns a list of tuples containing the id of the annotation and the id of the requirement,
149+ and the distance between their embeddings (anno_id, req_id, distance).
150+ The distance is calculated using the L2 norm. The results are ordered by requirement ID and distance.
151+ """
152+ cursor = self .conn .execute ("""
153+ SELECT
154+ Annotations.id AS anno_id,
155+ Requirements.id AS req_id,
156+ vec_distance_L2(Annotations.embedding, Requirements.embedding) AS distance
157+ FROM Annotations, Requirements
158+ WHERE Annotations.embedding IS NOT NULL AND Requirements.embedding IS NOT NULL
159+ ORDER BY req_id, distance
160+ """ )
161+ return cursor .fetchall ()
162+
163+ def get_embeddings_from_annotations_to_requirements_table (self ):
164+ """
165+ Returns a list of annotation's embeddings that are stored in the AnnotationsToRequirements table.
166+ The embeddings are ordered by annotation ID.
167+ """
168+ cursor = self .conn .execute ("""
169+ SELECT embedding FROM Annotations
170+ WHERE id IN (
171+ SELECT DISTINCT annotation_id FROM AnnotationsToRequirements
172+ )
173+ """ )
174+ return cursor .fetchall ()
175+
176+ def join_all_tables_by_requirements (
177+ self , where_clauses = "" , params = None
178+ ) -> list [tuple ]:
179+ """
180+ Join all tables related to requirements based on the provided where clauses and parameters.
181+ return a list of tuples containing :
182+ req_id,
183+ req_external_id,
184+ req_summary,
185+ req_embedding,
186+ anno_id,
187+ anno_summary,
188+ anno_embedding,
189+ distance,
190+ case_id,
191+ test_script,
192+ test_case
193+ """
194+ where_sql = f"WHERE { ' AND ' .join (where_clauses )} " if where_clauses else ""
195+ sql = f"""
196+ SELECT
197+ Requirements.id as req_id,
198+ Requirements.external_id as req_external_id,
199+ Requirements.summary as req_summary,
200+ Requirements.embedding as req_embedding,
201+
202+ Annotations.id as anno_id,
203+ Annotations.summary as anno_summary,
204+ Annotations.embedding as anno_embedding,
205+
206+ AnnotationsToRequirements.cached_distance as distance,
207+
208+ TestCases.id as case_id,
209+ TestCases.test_script as test_script,
210+ TestCases.test_case as test_case
211+ FROM
212+ Requirements
213+ JOIN AnnotationsToRequirements ON Requirements.id = AnnotationsToRequirements.requirement_id
214+ JOIN Annotations ON Annotations.id = AnnotationsToRequirements.annotation_id
215+ JOIN CasesToAnnos ON Annotations.id = CasesToAnnos.annotation_id
216+ JOIN TestCases ON TestCases.id = CasesToAnnos.case_id
217+ { where_sql }
218+ ORDER BY
219+ Requirements.id, AnnotationsToRequirements.cached_distance, TestCases.id
220+ LIMIT ?
221+ """
222+ data = self .conn .execute (sql , params )
223+ return data .fetchall ()
224+
225+ def get_ordered_values_from_requirements (
226+ self , distance_sql = "" , where_clauses = "" , distance_order_sql = "" , params = None
227+ ) -> list [tuple ]:
228+ where_sql = f"WHERE { ' AND ' .join (where_clauses )} " if where_clauses else ""
229+ sql = f"""
230+ SELECT
231+ Requirements.id as req_id,
232+ Requirements.external_id as req_external_id,
233+ Requirements.summary as req_summary
234+ { distance_sql }
235+ FROM
236+ Requirements
237+ { where_sql }
238+ ORDER BY
239+ { distance_order_sql } Requirements.id
240+ """
241+ data = self .conn .execute (sql , params )
242+ return data .fetchall ()
243+
244+ def get_ordered_values_from_test_cases (
245+ self , distance_sql = "" , where_clauses = "" , distance_order_sql = "" , params = None
246+ ) -> list [tuple ]:
247+ where_sql = f"WHERE { ' AND ' .join (where_clauses )} " if where_clauses else ""
248+ sql = f"""
249+ SELECT
250+ TestCases.id as case_id,
251+ TestCases.test_script as test_script,
252+ TestCases.test_case as test_case
253+ { distance_sql }
254+ FROM
255+ TestCases
256+ { where_sql }
257+ ORDER BY
258+ { distance_order_sql } TestCases.id
259+ """
260+ data = self .conn .execute (sql , params )
261+ return data .fetchall ()
262+
263+ def join_all_tables_by_test_cases (
264+ self , where_clauses = "" , params = None
265+ ) -> list [tuple ]:
266+ where_sql = ""
267+ if where_clauses :
268+ where_sql = f"WHERE { ' AND ' .join (where_clauses )} "
269+
270+ sql = f"""
271+ SELECT
272+ TestCases.id as case_id,
273+ TestCases.test_script as test_script,
274+ TestCases.test_case as test_case,
275+
276+ Annotations.id as anno_id,
277+ Annotations.summary as anno_summary,
278+ Annotations.embedding as anno_embedding,
279+
280+ AnnotationsToRequirements.cached_distance as distance,
281+
282+ Requirements.id as req_id,
283+ Requirements.external_id as req_external_id,
284+ Requirements.summary as req_summary,
285+ Requirements.embedding as req_embedding
286+ FROM
287+ TestCases
288+ JOIN CasesToAnnos ON TestCases.id = CasesToAnnos.case_id
289+ JOIN Annotations ON Annotations.id = CasesToAnnos.annotation_id
290+ JOIN AnnotationsToRequirements ON Annotations.id = AnnotationsToRequirements.annotation_id
291+ JOIN Requirements ON Requirements.id = AnnotationsToRequirements.requirement_id
292+ { where_sql }
293+ ORDER BY
294+ case_id, distance, req_id
295+ LIMIT ?
296+ """
297+ data = self .conn .execute (sql , params )
298+ return data .fetchall ()
0 commit comments