fewsvisualiser 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ __version__ = "1.0.1"
2
+
3
+ from fewsvisualiser.analyse import analyse_config
4
+ from fewsvisualiser.explore import explore_config
5
+ from fewsvisualiser.locset_analysis import locset_analysis
6
+
7
+ __all__ = [
8
+ "analyse_config",
9
+ "explore_config",
10
+ "locset_analysis",
11
+ ]
@@ -0,0 +1,8 @@
1
+ import fire
2
+ from fewsvisualiser.analyse import analyse_config
3
+ from fewsvisualiser.explore import explore_config
4
+ from fewsvisualiser.locset_analysis import locset_analysis
5
+
6
+
7
+ if __name__ == "__main__":
8
+ fire.Fire()
@@ -0,0 +1,61 @@
1
+ from pathlib import Path
2
+ from fewsvisualiser.core.dbconfigvis import DbConfigVis
3
+ from fewsvisualiser.core.fewsparsers import Workflows_parser, TimeseriesSetParser, Modins_parser, Endpoint_parsers, CoefficientSet_parser, ModuleInstanceDescriptorParser, ModuleInstanceSetsParser
4
+ from fewsvisualiser.core.helpers import setup_logging, delete_file
5
+
6
+
7
+ #=======================================================================================
8
+ # MAIN PROGRAM
9
+ def analyse_config(croot, dbpath):
10
+ # Convert to Path objects
11
+ dbpath_obj = Path(dbpath)
12
+
13
+ # Extract the database name for the log file
14
+ db_name = dbpath_obj.stem
15
+ log_file = dbpath_obj.parent / f"{db_name}.log"
16
+
17
+ # Ensure we start with clean files
18
+ delete_file(log_file) # Clean log file
19
+ delete_file(dbpath) # Clean database file
20
+
21
+ # Setup logging
22
+ global logger
23
+ logger = setup_logging(__name__, str(log_file))
24
+
25
+ logger.info(f"root: {croot}")
26
+ logger.info(f"Log file: {log_file}")
27
+ logger.info(f"Starting with clean database: {dbpath}")
28
+ config_root = Path(croot)
29
+
30
+ db = DbConfigVis(dbpath, logger)
31
+ db.create_tables(logger)
32
+
33
+ # parsing workflow descriptors
34
+ Workflows_parser.parse_workflow_descriptors(config_root, db, logger)
35
+ # parsing workflow files
36
+ Workflows_parser.loop_workflows(config_root, db, logger)
37
+
38
+ #db.close(logger)
39
+ #exit(0)
40
+ #db.clear_tables(logger)
41
+
42
+ # parsing TimeSteps
43
+ TimeseriesSetParser.parse_timestep_id_file(config_root / "RegionConfigFiles/TimeSteps.xml", logger)
44
+ # parsing ModuleInstanceDescriptors
45
+ ModuleInstanceDescriptorParser.parse_moduleinstances_file(db, config_root, logger)
46
+ # parsing ModuleInstanceSets
47
+ ModuleInstanceSetsParser.parse_moduleinstancesets_file(db, config_root, logger)
48
+ # parsing filter files
49
+ Endpoint_parsers.parse_endpoint(db, config_root / "RegionConfigFiles", 'filters', logger)
50
+ # parsing displayGroups files
51
+ Endpoint_parsers.parse_endpoint(db, config_root / "SystemConfigFiles", 'displayGroups', logger)
52
+ # parsing gridDisplay files
53
+ Endpoint_parsers.parse_endpoint(db, config_root / "DisplayConfigFiles", 'gridDisplay', logger)
54
+ # parsing scadaDisplay (schematic displays) files
55
+ Endpoint_parsers.parse_endpoint(db, config_root / "DisplayConfigFiles", 'scadaDisplay', logger)
56
+ # parsing transformationCoefficientSets
57
+ CoefficientSet_parser.parse(config_root / "CoefficientSetsFiles", logger)
58
+ # parsing module instance files
59
+ Modins_parser.parse_modins(db, config_root, logger)
60
+
61
+ db.close(logger)
File without changes
@@ -0,0 +1,401 @@
1
+ import sqlite3
2
+
3
+ class DbConfigVis:
4
+ def __init__(self, dbpath, logger):
5
+ try:
6
+ self.con = sqlite3.connect(database=dbpath)
7
+ logger.info("Successfully connected to SQLite")
8
+ version = sqlite3.sqlite_version_info
9
+ logger.debug(f"SQLite Database Version is: {version}")
10
+ except sqlite3.Error as error:
11
+ logger.error("Error while connecting to SQLite", error)
12
+ exit(1)
13
+
14
+ def create_tables(self, logger):
15
+ cursor = self.con.cursor()
16
+
17
+ dll_props_sets_table = """CREATE TABLE props_sets (
18
+ id INTEGER NOT NULL,
19
+ key TEXT NOT NULL,
20
+ value TEXT NOT NULL,
21
+ CONSTRAINT PK_props_sets PRIMARY KEY (id, key))"""
22
+ cursor.execute(dll_props_sets_table)
23
+ logger.info("props_sets table created")
24
+
25
+ dll_call_stacks_table = """CREATE TABLE call_stacks (
26
+ id INTEGER NOT NULL,
27
+ wf_id TEXT NOT NULL,
28
+ description TEXT,
29
+ wffn TEXT NOT NULL,
30
+ parent_id INTEGER,
31
+ props_set_id INTEGER,
32
+ CONSTRAINT PK_call_stacks PRIMARY KEY (id),
33
+ FOREIGN KEY(props_set_id) REFERENCES props_sets(id),
34
+ FOREIGN KEY(parent_id) REFERENCES call_stacks(id))"""
35
+ cursor.execute(dll_call_stacks_table)
36
+ logger.info("call_stacks table created")
37
+
38
+ dll_modins_calls_table = """CREATE TABLE modins_calls (
39
+ id INTEGER NOT NULL,
40
+ call_stack_id INTEGER NOT NULL,
41
+ modins TEXT NOT NULL,
42
+ props_set_id INTEGER,
43
+ description TEXT,
44
+ CONSTRAINT PK_modins_calls PRIMARY KEY (id, call_stack_id),
45
+ FOREIGN KEY(props_set_id) REFERENCES props_sets(id),
46
+ FOREIGN KEY(call_stack_id) REFERENCES call_stacks(id))"""
47
+ cursor.execute(dll_modins_calls_table)
48
+ logger.info("modins_calls table created")
49
+
50
+ dll_timeseries_sets_table = """CREATE TABLE ts_sets (
51
+ id INTEGER NOT NULL,
52
+ modins TEXT NOT NULL,
53
+ vtype TEXT NOT NULL,
54
+ parid TEXT NOT NULL,
55
+ qualifiers TEXT,
56
+ tstype TEXT NOT NULL,
57
+ timess TEXT NOT NULL,
58
+ aggregation TEXT,
59
+ description TEXT,
60
+ CONSTRAINT PK_ts_sets PRIMARY KEY (id)
61
+ )"""
62
+ cursor.execute(dll_timeseries_sets_table)
63
+ logger.info("ts_sets table created")
64
+
65
+ dll_trafos_table = """CREATE TABLE trafos (
66
+ idx INTEGER NOT NULL,
67
+ mic_id INTEGER NOT NULL,
68
+ ord_nr INTEGER NOT NULL,
69
+ trafo_id TEXT NOT NULL,
70
+ description TEXT,
71
+ config_file TEXT NOT NULL,
72
+ CONSTRAINT PK_trafos PRIMARY KEY (idx),
73
+ UNIQUE(mic_id, ord_nr),
74
+ FOREIGN KEY(mic_id) REFERENCES modins_calls(id)
75
+ )"""
76
+ cursor.execute(dll_trafos_table)
77
+ logger.info("trafos table created")
78
+
79
+ dll_links_table = """CREATE TABLE links (
80
+ trafo_idx INTEGER NOT NULL,
81
+ tss_id INTEGER NOT NULL,
82
+ inout TEXT,
83
+ UNIQUE(trafo_idx, tss_id, inout),
84
+ FOREIGN KEY(trafo_idx) REFERENCES trafos(idx),
85
+ FOREIGN KEY(tss_id) REFERENCES ts_sets(id)
86
+ )"""
87
+ cursor.execute(dll_links_table)
88
+ logger.info("links table created")
89
+
90
+ dll_endpoints_table = """CREATE TABLE endpoints (
91
+ tss_id INTEGER NOT NULL,
92
+ description TEXT NOT NULL,
93
+ CONSTRAINT PK_endpoints PRIMARY KEY (tss_id, description),
94
+ FOREIGN KEY(tss_id) REFERENCES ts_sets(id)
95
+ )"""
96
+ cursor.execute(dll_endpoints_table)
97
+ logger.info("endpoints table created")
98
+
99
+ dll_moduleinstances_table = """CREATE TABLE moduleinstances (
100
+ modin_id TEXT NOT NULL,
101
+ name TEXT NOT NULL,
102
+ CONSTRAINT PK_moduleinstances PRIMARY KEY (modin_id))"""
103
+ cursor.execute(dll_moduleinstances_table)
104
+ logger.info("moduleinstances table created")
105
+
106
+ dll_moduleinstancesets_table = """CREATE TABLE moduleinstancesets (
107
+ set_id TEXT NOT NULL,
108
+ mid TEXT,
109
+ mip TEXT)"""
110
+ cursor.execute(dll_moduleinstancesets_table)
111
+ logger.info("moduleinstancesets table created")
112
+
113
+ self.con.commit()
114
+ logger.info("Database created")
115
+
116
+ def get_n_call_stacks(self):
117
+ row = self.con.execute("SELECT count(*) FROM call_stacks").fetchone()
118
+ return row[0]
119
+
120
+ def get_n_modins_calls(self):
121
+ row = self.con.execute("SELECT count(*) FROM modins_calls").fetchone()
122
+ return row[0]
123
+
124
+ def get_max_trafos_idx(self) -> int:
125
+ row = self.con.execute("SELECT MAX(idx) FROM trafos").fetchone()
126
+ return int(row[0]) if row[0] else 0
127
+
128
+ def get_max_call_stacks_id(self) -> int:
129
+ row = self.con.execute("SELECT MAX(id) FROM call_stacks").fetchone()
130
+ return int(row[0]) if row[0] else 0
131
+
132
+ def get_max_props_sets_id(self) -> int:
133
+ row = self.con.execute("SELECT MAX(id) FROM props_sets").fetchone()
134
+ return int(row[0]) if row[0] else 0
135
+
136
+ def get_max_modins_calls_id(self) -> int:
137
+ row = self.con.execute("SELECT MAX(id) FROM modins_calls").fetchone()
138
+ return int(row[0]) if row[0] else 0
139
+
140
+ def get_call_stack_from_wfid(self, wf_id, logger):
141
+ try:
142
+ cursor = self.con.cursor()
143
+ cs = self.con.execute("SELECT id, description, wffn, props_set_id FROM call_stacks WHERE wf_id =:wf_id", {"wf_id": wf_id}).fetchone()
144
+ except sqlite3.Error as error:
145
+ logger.error(error)
146
+ finally:
147
+ cursor.close()
148
+ return cs
149
+
150
+ def get_tss(self, tss_id, logger):
151
+ try:
152
+ return self.con.execute("SELECT * FROM ts_sets WHERE id =:id", {"id": tss_id}).fetchone()
153
+ except sqlite3.Error as error:
154
+ logger.error(error)
155
+ raise
156
+
157
+ def get_trafo_index(self, mic_id, ord_nr, trafo_id, trafo_description, config_file, logger):
158
+ try:
159
+ cursor = self.con.cursor()
160
+ # find trafo_id
161
+ trafo_row = self.con.execute("SELECT idx FROM trafos WHERE mic_id=:mic_id AND ord_nr=:ord_nr", {"mic_id": mic_id, "ord_nr": ord_nr}).fetchone()
162
+ if trafo_row is None:
163
+ idx = self.get_max_trafos_idx() + 1
164
+ insert_statement = """INSERT INTO 'trafos' ('idx','mic_id','ord_nr','trafo_id','description','config_file') VALUES (?, ?, ?, ?, ?, ?);"""
165
+ cursor.execute(insert_statement, (idx, mic_id, ord_nr, trafo_id, trafo_description, config_file))
166
+ self.con.commit()
167
+ else:
168
+ idx = trafo_row[0]
169
+ except sqlite3.Error as error:
170
+ logger.error(error)
171
+ idx = None
172
+ raise
173
+ finally:
174
+ cursor.close()
175
+ return idx
176
+
177
+ def add_inoutput(self, mic_id, ord_nr, trafo_id, trafo_description, config_file, tss_id, direction, logger):
178
+ trafo_idx = self.get_trafo_index(mic_id, ord_nr, trafo_id, trafo_description, config_file, logger)
179
+ try:
180
+ cursor = self.con.cursor()
181
+ insert_statement = """INSERT INTO 'links' ('trafo_idx','tss_id','inout') VALUES (?, ?, ?);"""
182
+ cursor.execute(insert_statement, (trafo_idx, tss_id, direction))
183
+ self.con.commit()
184
+ except sqlite3.IntegrityError as error:
185
+ pass
186
+ except sqlite3.Error as error:
187
+ logger.warn(error)
188
+ raise
189
+ finally:
190
+ cursor.close()
191
+
192
+ def add_input(self, mic_id, ord_nr, trafo_id, description, config_file, tss_id, logger):
193
+ self.add_inoutput(mic_id, ord_nr, trafo_id, description, config_file, tss_id, 'in', logger)
194
+
195
+ def add_output(self, mic_id, ord_nr, trafo_id, description, config_file, tss_id, logger):
196
+ self.add_inoutput(mic_id, ord_nr, trafo_id, description, config_file, tss_id, 'out', logger)
197
+
198
+ def insert_props_set(self, properties_set, logger) -> int:
199
+ if not properties_set:
200
+ return None
201
+ new_ps_id = self.get_max_props_sets_id() + 1
202
+ try:
203
+ cursor = self.con.cursor()
204
+ for key, value in properties_set.items():
205
+ data = (new_ps_id, key, value)
206
+ try:
207
+ insert_statement = """INSERT INTO 'props_sets' ('id','key','value') VALUES (?, ?, ?);"""
208
+ logger.debug("INSERT INTO props_sets: {}".format(data))
209
+ cursor.execute(insert_statement, data)
210
+ except sqlite3.IntegrityError as error:
211
+ logger.error(error)
212
+ logger.warn("property overwritten: {}: {}".format(key, value))
213
+ update_statement = """UPDATE 'props_sets' SET value = ? WHERE id = ? AND key = ?"""
214
+ cursor.execute(update_statement, (value, new_ps_id, key))
215
+ self.con.commit()
216
+ finally:
217
+ cursor.close()
218
+ return new_ps_id
219
+
220
+
221
+ def add_call_stack(self, wfid, desc, wffn, parent, psid) -> int:
222
+ try:
223
+ cursor = self.con.cursor()
224
+ ccs_id = self.get_max_call_stacks_id() + 1
225
+ # create a new call stack
226
+ data = (ccs_id, wfid, desc, wffn, parent, psid)
227
+ insert_statement = """INSERT INTO 'call_stacks' ('id','wf_id','description','wffn','parent_id','props_set_id') VALUES (?,?,?,?,?,?);"""
228
+ cursor.execute(insert_statement, data)
229
+ self.con.commit()
230
+ finally:
231
+ cursor.close()
232
+ return ccs_id
233
+
234
+ def add_modins_calls(self, modfn, csid, psid, desc):
235
+ try:
236
+ cursor = self.con.cursor()
237
+ mic_id = self.get_max_modins_calls_id() + 1
238
+ data = (mic_id, csid, modfn, psid, desc)
239
+ insert_statement = """INSERT INTO 'modins_calls' ('id', 'call_stack_id', 'modins', 'props_set_id', 'description') VALUES (?, ?, ?, ?, ?);"""
240
+ cursor.execute(insert_statement, data)
241
+ self.con.commit()
242
+ finally:
243
+ cursor.close()
244
+
245
+ def wfs_insert(self, wf_id, wf_desc, wf_fn, cps_id):
246
+ try:
247
+ cursor = self.con.cursor()
248
+ data = (wf_id, wf_desc, wf_fn, cps_id)
249
+ insert_statement = """INSERT INTO 'wfs' ('id','description','filename', 'props_set_id') VALUES (?, ?, ?, ?);"""
250
+ cursor.execute(insert_statement, data)
251
+ self.con.commit()
252
+ finally:
253
+ cursor.close()
254
+
255
+ def mid_insert(self, mi_id, mi_name, logger):
256
+ try:
257
+ cursor = self.con.cursor()
258
+ data = (mi_id, mi_name)
259
+ insert_statement = """INSERT INTO 'moduleinstances' ('modin_id', 'name') VALUES (?, ?);"""
260
+ cursor.execute(insert_statement, data)
261
+ self.con.commit()
262
+ except sqlite3.IntegrityError('UNIQUE constraint failed: moduleinstances.modin_id') as error:
263
+ logger.error(error)
264
+ logger.warning("Module instance already exists: {}: {}".format(mi_id, mi_name))
265
+ logger.error('Check for duplicate modules instances in RegionConfigFiles/ModuleInstanceDescriptors.xml')
266
+ finally:
267
+ cursor.close()
268
+
269
+ def miset_insert(self, mis_id, mid, mip):
270
+ try:
271
+ cursor = self.con.cursor()
272
+ data = (mis_id, mid, mip)
273
+ insert_statement = """INSERT INTO 'moduleinstancesets' ('set_id', 'mid', 'mip') VALUES (?, ?, ?);"""
274
+ cursor.execute(insert_statement, data)
275
+ self.con.commit()
276
+ finally:
277
+ cursor.close()
278
+
279
+ def list_wfs(self):
280
+ return self.con.execute("SELECT id, wf_id, wffn, props_set_id FROM call_stacks").fetchall()
281
+
282
+ def list_modins(self):
283
+ return self.con.execute("SELECT id, modins, call_stack_id, props_set_id FROM modins_calls ORDER BY modins ASC").fetchall()
284
+
285
+ def get_props_set(self, id, logger):
286
+ try:
287
+ props = {}
288
+ [props.update({row[0]: row[1]}) for row in self.con.execute("SELECT key, value FROM props_sets WHERE id =:id", {"id": id}).fetchall()]
289
+ return props
290
+ except sqlite3.Error as error:
291
+ logger.error("Error get_props_set: ", error)
292
+ raise
293
+
294
+ def add_tts(self, tss, logger):
295
+ try:
296
+ # tss_id
297
+ tss_id_row = self.con.execute("SELECT MAX(id) FROM ts_sets").fetchone()
298
+ if tss_id_row[0] is None:
299
+ tss_id = 1
300
+ else:
301
+ tss_id = int(tss_id_row[0]) + 1
302
+
303
+ cursor = self.con.cursor()
304
+ data = (tss_id, ) + tss
305
+ insert_statement = """INSERT INTO 'ts_sets' ('id', 'modins', 'vtype', 'parid', 'qualifiers', 'tstype', 'timess', 'aggregation', 'description') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);"""
306
+ cursor.execute(insert_statement, data)
307
+ self.con.commit()
308
+ except sqlite3.Error as error:
309
+ logger.error("Error add_tts: ", error)
310
+ finally:
311
+ cursor.close()
312
+ return tss_id
313
+
314
+ def get_tss_id(self, tss, logger):
315
+ try:
316
+ select_statement = "SELECT id, description FROM ts_sets WHERE modins = ? AND vtype = ? AND parid = ? AND qualifiers = ? AND tstype = ? AND timess = ? AND aggregation = ?"
317
+ # the eighth elem is the description, which is optional
318
+ desc_id = 7
319
+ row = self.con.execute(select_statement, tss[0:desc_id]).fetchone()
320
+ if row is None:
321
+ tss_id = self.add_tts(tss, logger)
322
+ else:
323
+ tss_id = row[0]
324
+ # append description if it exists
325
+ if tss[7]:
326
+ if not tss[desc_id].lower() in row[1].lower():
327
+ # update the description
328
+ logger.info(f"Updating description for tss_id {tss_id}")
329
+ if row[1]:
330
+ new_description = row[1] + "; " + tss[desc_id].lower()
331
+ else:
332
+ new_description = tss[desc_id].lower()
333
+ update_statement = "UPDATE ts_sets SET description = ? WHERE id = ?"
334
+ self.con.execute(update_statement, (new_description, tss_id))
335
+ self.con.commit()
336
+ except sqlite3.Error as error:
337
+ logger.error("Error get_tss_id: ", error)
338
+ raise
339
+ return tss_id
340
+
341
+ def add_endpoint(self, tss_id, desc, logger):
342
+ try:
343
+ cursor = self.con.cursor()
344
+ insert_statement = """INSERT INTO 'endpoints' ('tss_id','description') VALUES (?, ?);"""
345
+ cursor.execute(insert_statement, (tss_id, desc))
346
+ self.con.commit()
347
+ except sqlite3.IntegrityError as error:
348
+ pass
349
+ except sqlite3.Error as error:
350
+ logger.error("Error add_endpoint: ", error)
351
+ raise
352
+ finally:
353
+ cursor.close()
354
+
355
+ def clear_tables(self, logger):
356
+ try:
357
+ cursor = self.con.cursor()
358
+ cursor.execute("DELETE FROM endpoints")
359
+ cursor.execute("DELETE FROM links")
360
+ cursor.execute("DELETE FROM trafos")
361
+ cursor.execute("DELETE FROM ts_sets")
362
+ self.con.commit()
363
+ except sqlite3.Error as error:
364
+ logger.error("Error clear_tables: ", error)
365
+ raise
366
+ finally:
367
+ cursor.close()
368
+
369
+ def close(self, logger):
370
+ try:
371
+ self.con.close()
372
+ logger.info("Db closed")
373
+ except sqlite3.Error as error:
374
+ logger.error("Error while closing to sqlite: ", error)
375
+ raise
376
+
377
+ def get_links_by_tss(self, tss_id, direction, logger):
378
+ try:
379
+ links = set()
380
+ data = {"tss_id": tss_id, "inout": direction}
381
+ [links.add(row) for row in self.con.execute("SELECT * FROM links WHERE tss_id =:tss_id AND inout =:inout", data).fetchall()]
382
+ return links
383
+ except sqlite3.Error as error:
384
+ logger.error(error)
385
+ raise
386
+
387
+ def get_links_by_trafo(self, trafo_id, direction, logger):
388
+ try:
389
+ links = set()
390
+ data = {"trafo_id": trafo_id, "inout": direction}
391
+ [links.add(row) for row in self.con.execute("SELECT * FROM links WHERE trafo_id =:trafo_id AND inout =:inout", data).fetchall()]
392
+ return links
393
+ except sqlite3.Error as error:
394
+ logger.error(error)
395
+ raise
396
+
397
+ def general_query(self, query, logger):
398
+ try:
399
+ return self.con.execute(query).fetchall()
400
+ except sqlite3.Error as error:
401
+ logger.error(error)
@@ -0,0 +1,79 @@
1
+ import sqlite3
2
+
3
+ class DbCLocSet:
4
+ def __init__(self, dbpath, logger):
5
+ try:
6
+ self.con = sqlite3.connect(database=dbpath)
7
+ logger.info("Successfully connected to SQLite")
8
+ version = sqlite3.sqlite_version_info
9
+ logger.debug(f"SQLite Database Version is: {version}")
10
+ except sqlite3.Error as error:
11
+ logger.error("Error while connecting to SQLite", error)
12
+ exit(1)
13
+
14
+ def create_tables(self, logger):
15
+ cursor = self.con.cursor()
16
+
17
+ dll_locsets_table = """CREATE TABLE locsets (
18
+ id TEXT NOT NULL,
19
+ name TEXT NOT NULL,
20
+ source TEXT NOT NULL,
21
+ CONSTRAINT PK_locsets_id PRIMARY KEY (id))"""
22
+ cursor.execute(dll_locsets_table)
23
+ logger.info("locsets table created")
24
+
25
+ dll_locsets_relations_table = """CREATE TABLE locsets_relations (
26
+ id TEXT NOT NULL,
27
+ parent_id TEXT,
28
+ FOREIGN KEY(parent_id) REFERENCES locsets(id))"""
29
+ cursor.execute(dll_locsets_relations_table)
30
+ logger.info("locsets_relations table created")
31
+
32
+ dll_attributes_table = """CREATE TABLE attributes (
33
+ id TEXT NOT NULL,
34
+ locset_id TEXT NOT NULL,
35
+ name TEXT,
36
+ source TEXT NOT NULL,
37
+ field TEXT NOT NULL,
38
+ FOREIGN KEY(locset_id) REFERENCES locsets(id))"""
39
+ cursor.execute(dll_attributes_table)
40
+ logger.info("attributes table created")
41
+ self.con.commit()
42
+
43
+
44
+ def insert_locset(self, locset, logger):
45
+ cursor = self.con.cursor()
46
+ try:
47
+ cursor.execute("INSERT INTO locsets (id, name, source) VALUES (?, ?, ?)",
48
+ (locset['id'], locset['name'], locset.get('source', '')))
49
+ self.con.commit()
50
+ logger.info(f"Inserted locset: {locset['id']}")
51
+ except sqlite3.Error as error:
52
+ logger.error(f"Error inserting locset {locset['id']}: {error}")
53
+
54
+
55
+ def insert_locset_relation(self, locset_id, parent_id, logger):
56
+ cursor = self.con.cursor()
57
+ try:
58
+ cursor.execute("INSERT INTO locsets_relations (id, parent_id) VALUES (?, ?)",
59
+ (locset_id, parent_id))
60
+ self.con.commit()
61
+ logger.info(f"Inserted locset relation: {locset_id} -> {parent_id}")
62
+ except sqlite3.Error as error:
63
+ logger.error(f"Error inserting locset relation {locset_id} -> {parent_id}: {error}")
64
+
65
+
66
+ def general_query(self, query, logger):
67
+ try:
68
+ return self.con.execute(query).fetchall()
69
+ except sqlite3.Error as error:
70
+ logger.error(error)
71
+
72
+
73
+ def close(self, logger):
74
+ try:
75
+ self.con.close()
76
+ logger.info("Db closed")
77
+ except sqlite3.Error as error:
78
+ logger.error("Error while closing to sqlite: ", error)
79
+ raise