.qetz: a property's show flag gets a column

The JSON column of a property row held only its show flag, in every
project QElectroTech saves: the 25 examples and a 136-folio project used
it for nothing else. Folio and project properties now store it as a
number, as symbol information does, so a saved project's database holds
no JSON; JSON is left for attributes QElectroTech does not write (an
older or hand-edited file).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-14 10:36:19 +13:00
parent 4c3d87e3f7
commit 590bd6e532
3 changed files with 53 additions and 37 deletions
+2 -2
View File
@@ -48,8 +48,8 @@ namespace QetContainer
/// The format written; files of a later format are refused by join()
/// unless their min-reader allows this one.
constexpr int Format = 3;
/// 3: the database's rows keyed by the items' uuids, true/false as
/// 1/0, its PRAGMA user_version the format, the symbols' type left
/// 3: the database's rows keyed by the items' uuids, true/false and
/// show flags as 1/0, its PRAGMA user_version the format, the symbols' type left
/// in the folio files, no column for where a block sat. Format 2 is
/// still read; a later format whose min-reader allows this one is
/// read too, and said so through join()'s @p format.
+31 -35
View File
@@ -121,11 +121,11 @@ QString schema()
{
return QStringLiteral(
"CREATE TABLE meta (key TEXT PRIMARY KEY, value TEXT);"
"CREATE TABLE project_property (ord INTEGER PRIMARY KEY, name TEXT, value TEXT, attrs TEXT);"
"CREATE TABLE project_property (ord INTEGER PRIMARY KEY, name TEXT, value TEXT, show INTEGER, attrs TEXT);"
"CREATE TABLE folio (uuid TEXT PRIMARY KEY, pos INTEGER NOT NULL UNIQUE, %1,"
" props_attrs TEXT);"
"CREATE TABLE folio_property (folio_uuid TEXT NOT NULL REFERENCES folio, ord INTEGER NOT NULL,"
" name TEXT, value TEXT, attrs TEXT, PRIMARY KEY (folio_uuid, ord));"
" name TEXT, value TEXT, show INTEGER, attrs TEXT, PRIMARY KEY (folio_uuid, ord));"
"CREATE TABLE element (uuid TEXT PRIMARY KEY, folio_uuid TEXT NOT NULL REFERENCES folio, %2,"
" info_attrs TEXT, links_attrs TEXT);"
"CREATE TABLE element_info (element_uuid TEXT NOT NULL REFERENCES element, ord INTEGER NOT NULL,"
@@ -455,6 +455,21 @@ QList<QDomElement> children(const QDomElement &parent, const QString &tag)
return list;
}
//A list entry -- a <property>, an <elementInformation> -- as its row:
//its name, value, show flag (0 or 1, else left in the JSON) and any
//other attribute as JSON, its tag too if it is not @p usual_tag
QVariantList entryRow(const QDomElement &e, const QString &usual_tag)
{
QVariant value;
simpleValue(e, &value);
const QString show = e.attribute(QStringLiteral("show"));
const bool show_stored = show == QLatin1String("0") || show == QLatin1String("1");
QStringList kept{QStringLiteral("name")};
if (show_stored) kept << QStringLiteral("show");
return {e.hasAttribute(QStringLiteral("name")) ? QVariant(e.attribute(QStringLiteral("name"))) : QVariant(),
value, show_stored ? QVariant(show.toInt()) : QVariant(), attributesJson(e, kept, usual_tag)};
}
//The key of each of @p items: its uuid, when it has one no other of
//@p items has, so the uuid the folio file already holds says which row
//is the item's (@p own true). Else (F100: symbols copied with their
@@ -510,9 +525,9 @@ QByteArray QetContainerDb::extract(QDomElement project, QString *error)
db.exec(QStringLiteral("BEGIN"));
Statement meta(db.m_db, QStringLiteral("INSERT INTO meta VALUES (?,?)"));
Statement project_property(db.m_db, QStringLiteral("INSERT INTO project_property VALUES (?,?,?,?)"));
Statement project_property(db.m_db, QStringLiteral("INSERT INTO project_property VALUES (?,?,?,?,?)"));
Statement folio(db.m_db, QStringLiteral("INSERT INTO folio VALUES (?,?,%1,?)").arg(placeholders(FolioData.size())));
Statement folio_property(db.m_db, QStringLiteral("INSERT INTO folio_property VALUES (?,?,?,?,?)"));
Statement folio_property(db.m_db, QStringLiteral("INSERT INTO folio_property VALUES (?,?,?,?,?,?)"));
Statement element(db.m_db, QStringLiteral("INSERT INTO element VALUES (?,?,%1,?,?)").arg(placeholders(ElementData.size())));
Statement element_info(db.m_db, QStringLiteral("INSERT INTO element_info VALUES (?,?,?,?,?,?)"));
Statement link(db.m_db, QStringLiteral("INSERT INTO link VALUES (?,?,?,?)"));
@@ -526,27 +541,15 @@ QByteArray QetContainerDb::extract(QDomElement project, QString *error)
//<properties> of a block, as rows of @p rows (with @p prefix values)
auto moveProperties = [&](QDomElement block, Statement &rows, const QVariantList &prefix) {
int ord = 0;
for (QDomElement p : children(block, QStringLiteral("property"))) {
QVariant value;
simpleValue(p, &value);
ok = ok && rows.run(QVariantList(prefix) << ord++ << (p.hasAttribute(QStringLiteral("name"))
? QVariant(p.attribute(QStringLiteral("name"))) : QVariant())
<< value << attributesJson(p, {QStringLiteral("name")}, QStringLiteral("property")));
}
for (QDomElement p : children(block, QStringLiteral("property")))
ok = ok && rows.run(QVariantList(prefix) << ord++ << entryRow(p, QStringLiteral("property")));
};
//Project properties
const QDomElement project_props = project.firstChildElement(QStringLiteral("properties"));
if (!project_props.isNull() && listBlock(project_props, QStringLiteral("property"))) {
ok = ok && meta.run({QStringLiteral("props_attrs"), blockJson(project_props)});
int ord = 0;
for (QDomElement p : children(project_props, QStringLiteral("property"))) {
QVariant value;
simpleValue(p, &value);
ok = ok && project_property.run({ord++, p.hasAttribute(QStringLiteral("name"))
? QVariant(p.attribute(QStringLiteral("name"))) : QVariant(),
value, attributesJson(p, {QStringLiteral("name")}, QStringLiteral("property"))});
}
moveProperties(project_props, project_property, {});
leaveMarker(project_props);
}
@@ -597,18 +600,9 @@ QByteArray QetContainerDb::extract(QDomElement project, QString *error)
ok = ok && element.run(erow);
if (!info.isNull()) {
int ord = 0;
for (QDomElement i : children(info, QStringLiteral("elementInformation"))) {
QVariant value;
simpleValue(i, &value);
const QString show = i.attribute(QStringLiteral("show"));
const bool show_stored = show == QLatin1String("0") || show == QLatin1String("1");
QStringList kept{QStringLiteral("name")};
if (show_stored) kept << QStringLiteral("show");
ok = ok && element_info.run({key, ord++, i.hasAttribute(QStringLiteral("name"))
? QVariant(i.attribute(QStringLiteral("name"))) : QVariant(),
value, show_stored ? QVariant(show.toInt()) : QVariant(),
attributesJson(i, kept, QStringLiteral("elementInformation"))});
}
for (QDomElement i : children(info, QStringLiteral("elementInformation")))
ok = ok && element_info.run(QVariantList{key, ord++}
<< entryRow(i, QStringLiteral("elementInformation")));
}
if (!links.isNull()) {
int ord = 0;
@@ -755,10 +749,11 @@ bool QetContainerDb::restore(QDomElement project, const QByteArray &database, QS
if (hasMarker(project, QStringLiteral("properties"))) {
QDomElement props = document.createElement(QStringLiteral("properties"));
setAttributesJson(props, meta.value(QStringLiteral("props_attrs")));
Statement s(db.m_db, QStringLiteral("SELECT name, value, attrs FROM project_property ORDER BY ord"));
Statement s(db.m_db, QStringLiteral("SELECT name, value, attrs, %1 FROM project_property ORDER BY ord")
.arg(show_column));
while (s.next())
props.appendChild(entry(s.value(0), QStringLiteral("name"), s.value(1), s.value(2),
QStringLiteral("property")));
QStringLiteral("property"), s.value(3)));
restoreWhitespace(props, meta.value(QStringLiteral("props_attrs")));
if (!replaceMarker(project, props)) {
setError(error, QStringLiteral("the project's properties have no place"));
@@ -812,11 +807,12 @@ bool QetContainerDb::restore(QDomElement project, const QByteArray &database, QS
if (hasMarker(d, QStringLiteral("properties"))) {
QDomElement props = document.createElement(QStringLiteral("properties"));
setAttributesJson(props, values.at(FolioData.size()));
Statement p(db.m_db, QStringLiteral("SELECT name, value, attrs FROM folio_property WHERE %1 = ? ORDER BY ord").arg(folio_ref));
Statement p(db.m_db, QStringLiteral("SELECT name, value, attrs, %1 FROM folio_property WHERE %2 = ? ORDER BY ord")
.arg(show_column, folio_ref));
p.bind({id});
while (p.next())
props.appendChild(entry(p.value(0), QStringLiteral("name"), p.value(1), p.value(2),
QStringLiteral("property")));
QStringLiteral("property"), p.value(3)));
restoreWhitespace(props, values.at(FolioData.size()));
if (!replaceMarker(d, props)) {
setError(error, QStringLiteral("folio %1's properties have no place").arg(id));
+20
View File
@@ -331,6 +331,26 @@ private slots:
QCOMPARE(query(database, "SELECT count(*) FROM meta WHERE key = 'props_at'"), QStringLiteral("0"));
}
// A project as QElectroTech saves it needs no JSON: every attribute it
// writes has a column, the show flag of a property too
void savedProjectNeedsNoJson()
{
QString error;
const QList<QetZip::Entry> entries = QetContainer::split(savedProject(), QString(), &error);
QVERIFY2(!entries.isEmpty(), qPrintable(error));
const QByteArray database = entry(entries, QStringLiteral("project.sqlite"));
QVERIFY(query(database, "SELECT count(*) FROM project_property").toInt() > 0);
QCOMPARE(query(database, "SELECT count(*) FROM project_property WHERE show IS NOT NULL"),
query(database, "SELECT count(*) FROM project_property"));
for (const char *sql : {"SELECT count(*) FROM project_property WHERE attrs IS NOT NULL",
"SELECT count(*) FROM folio_property WHERE attrs IS NOT NULL",
"SELECT count(*) FROM element_info WHERE attrs IS NOT NULL",
"SELECT count(*) FROM link WHERE attrs IS NOT NULL",
"SELECT count(*) FROM folio WHERE props_attrs IS NOT NULL",
"SELECT count(*) FROM element WHERE info_attrs IS NOT NULL OR links_attrs IS NOT NULL"})
QVERIFY2(query(database, sql) == QLatin1String("0"), sql);
}
void laterFormatRefused()
{
QDomDocument original;