mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-27 20:44:13 +02:00
Let a script query the project database
Every structural question this API could answer, it answered by walking live objects. The project builds a SQLite database that already knows most of them, and nothing outside the application could reach it. tables() what is queryable, tables and views query(sql) rows, one object per row queryError() why the last one returned nothing This is not a new door. QElectroTech already ships a "Requête SQL personnalisée" box in the element-query dialog where a user types arbitrary SQL, guarded by projectDataBase::isReadOnlySelect(); query() goes through projectDataBase::newQuery(), which applies that same rule and returns the same rejection message. A script gets what a user already has, and neither can write: DELETE, UPDATE and a chained "SELECT 1; DROP TABLE" are all refused before reaching SQLite. An empty result and a failure are told apart. query() returns no rows for both, so queryError() carries the reason -- a refusal, or SQLite's own message for a bad column -- and is empty when the query simply matched nothing. Conflating those is how a silent typo in a column name becomes "there are no such elements". No updateDB() before querying, and that is a measured decision rather than an omission. A script that has just edited something is the expected caller, so a stale cache was the obvious hazard; but projectDataBase maintains itself incrementally through addElement(), elementInfoChanged(), addConductor() and the rest, which the undo commands behind every edit already call. Tested both ways on the cases most likely to go stale -- an element added and labelled, a conductor property changed -- each queried immediately afterwards through both the table and the view. Identical counts with the rebuild and without it, and updateDB() repopulates every table, so calling it per query would have been real cost for no benefit. The comment says so, so it is not added back on the assumption it must be needed. The views are the surface to depend on: element_nomenclature_view, project_summary_view and wiring_list_view exist to be queried. The tables are how the cache is arranged today and a column may move -- which is why tables() lists both and the header says which is which. Verified against examples/industrial.qet, the largest shipped project: 618 elements counted, the busiest wire numbers ranked (0VDC 93 times, 24V2 64), and duplicate element labels found by GROUP BY ... HAVING -- V6 seven times, V5 six -- which is a design-rule question no tool here could previously ask. Qt 6.10.2, ctest matches master. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QVariantList>
|
||||
|
||||
class QETProject;
|
||||
class DiagramView;
|
||||
@@ -133,6 +134,22 @@ class QetShapeItem;
|
||||
deleting one: indexes after the affected position shift, the way a
|
||||
list's do. Call texts() or shapes() again rather than holding an
|
||||
index across an edit that adds or removes one.
|
||||
- @b Querying the project database: run a read-only SELECT against the
|
||||
SQLite database QElectroTech builds from the project, and get rows
|
||||
back as objects. This is not a new door. QET already ships a
|
||||
"Requête SQL personnalisée" box in the element-query dialog where a
|
||||
user types arbitrary SQL, and it is guarded by the same
|
||||
projectDataBase::isReadOnlySelect() this calls through
|
||||
projectDataBase::newQuery(). A script gets what a user already has,
|
||||
under the same rule, and neither can write.
|
||||
|
||||
What is worth knowing is what the database @b is: a cache, rebuilt
|
||||
from the XML on every load and never written to disk. The three
|
||||
views -- element_nomenclature_view, project_summary_view and
|
||||
wiring_list_view -- exist to be queried and are the surface to
|
||||
depend on. The underlying tables are how the cache happens to be
|
||||
arranged today, and a column may move. tables() lists both so a
|
||||
script can see what it is querying rather than guess.
|
||||
- @b Navigating and @b messaging: select an element, zoom the active
|
||||
view, and show the user a message. Deliberately narrow: selection and
|
||||
messaging work with no view at all (headless `--run`); zoom is a no-op
|
||||
@@ -241,6 +258,11 @@ class QetScriptApi : public QObject
|
||||
double x1, double y1, double x2, double y2);
|
||||
Q_INVOKABLE bool deleteShape(int folioIndex, int shapeIndex);
|
||||
|
||||
// -- query the project database --
|
||||
Q_INVOKABLE QStringList tables() const;
|
||||
Q_INVOKABLE QVariantList query(const QString &sql);
|
||||
Q_INVOKABLE QString queryError() const;
|
||||
|
||||
// -- folios --
|
||||
Q_INVOKABLE int addFolio();
|
||||
Q_INVOKABLE bool setFolioTitle(int folioIndex, const QString &title);
|
||||
@@ -276,6 +298,7 @@ class QetScriptApi : public QObject
|
||||
|
||||
QETProject *m_project;
|
||||
DiagramView *m_view;
|
||||
QString m_query_error;
|
||||
};
|
||||
|
||||
#endif // QET_SCRIPT_API_H
|
||||
|
||||
Reference in New Issue
Block a user