Step 410: add SQL AST nodes with serialization support
This commit is contained in:
@@ -2569,4 +2569,13 @@ target_link_libraries(step409_test PRIVATE
|
||||
tree_sitter_javascript tree_sitter_typescript
|
||||
tree_sitter_java tree_sitter_rust tree_sitter_go)
|
||||
|
||||
add_executable(step410_test tests/step410_test.cpp)
|
||||
target_include_directories(step410_test PRIVATE src)
|
||||
target_link_libraries(step410_test PRIVATE
|
||||
nlohmann_json::nlohmann_json
|
||||
unofficial::tree-sitter::tree-sitter
|
||||
tree_sitter_python tree_sitter_cpp tree_sitter_elisp
|
||||
tree_sitter_javascript tree_sitter_typescript
|
||||
tree_sitter_java tree_sitter_rust tree_sitter_go)
|
||||
|
||||
# Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "ast/Serialization.h"
|
||||
#include "ast/Annotation.h"
|
||||
#include "ast/HostBoundary.h"
|
||||
#include "ast/SqlNodes.h"
|
||||
#include "ASTUtils.h"
|
||||
#include "EnvironmentSpec.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
@@ -431,7 +432,6 @@ inline std::string getNodeName(const ASTNode* node) {
|
||||
return static_cast<const PragmaDirective*>(node)->directive;
|
||||
if (ct == "MacroDefinition")
|
||||
return static_cast<const MacroDefinition*>(node)->name;
|
||||
// Enum/Namespace/TypeAlias (Step 338)
|
||||
if (ct == "EnumDeclaration")
|
||||
return static_cast<const EnumDeclaration*>(node)->name;
|
||||
if (ct == "EnumMember")
|
||||
@@ -440,6 +440,24 @@ inline std::string getNodeName(const ASTNode* node) {
|
||||
return static_cast<const NamespaceDeclaration*>(node)->name;
|
||||
if (ct == "TypeAlias")
|
||||
return static_cast<const TypeAlias*>(node)->aliasName;
|
||||
if (ct == "TableDeclaration")
|
||||
return static_cast<const TableDeclaration*>(node)->name;
|
||||
if (ct == "ColumnDefinition")
|
||||
return static_cast<const ColumnDefinition*>(node)->name;
|
||||
if (ct == "SelectQuery")
|
||||
return "select";
|
||||
if (ct == "InsertStatement")
|
||||
return static_cast<const InsertStatement*>(node)->tableName;
|
||||
if (ct == "UpdateStatement")
|
||||
return static_cast<const UpdateStatement*>(node)->tableName;
|
||||
if (ct == "DeleteStatement")
|
||||
return static_cast<const DeleteStatement*>(node)->tableName;
|
||||
if (ct == "JoinClause")
|
||||
return static_cast<const JoinClause*>(node)->tableName;
|
||||
if (ct == "WhereClause")
|
||||
return "where";
|
||||
if (ct == "IndexDefinition")
|
||||
return static_cast<const IndexDefinition*>(node)->name;
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "AsyncNodes.h"
|
||||
#include "PreprocessorNodes.h"
|
||||
#include "EnumNamespaceNodes.h"
|
||||
#include "SqlNodes.h"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -546,6 +547,50 @@ inline json propertiesToJson(const ASTNode* node) {
|
||||
props["targetType"] = n->targetType;
|
||||
if (!n->isUsing) props["isUsing"] = n->isUsing;
|
||||
}
|
||||
// SQL nodes (Step 410)
|
||||
else if (ct == "TableDeclaration") {
|
||||
auto* n = static_cast<const TableDeclaration*>(node);
|
||||
if (!n->name.empty()) props["name"] = n->name;
|
||||
if (!n->schema.empty()) props["schema"] = n->schema;
|
||||
}
|
||||
else if (ct == "ColumnDefinition") {
|
||||
auto* n = static_cast<const ColumnDefinition*>(node);
|
||||
if (!n->name.empty()) props["name"] = n->name;
|
||||
if (!n->dataType.empty()) props["dataType"] = n->dataType;
|
||||
props["nullable"] = n->nullable;
|
||||
if (!n->defaultValue.empty()) props["defaultValue"] = n->defaultValue;
|
||||
}
|
||||
else if (ct == "SelectQuery") {
|
||||
auto* n = static_cast<const SelectQuery*>(node);
|
||||
if (n->distinct) props["distinct"] = n->distinct;
|
||||
}
|
||||
else if (ct == "InsertStatement") {
|
||||
auto* n = static_cast<const InsertStatement*>(node);
|
||||
if (!n->tableName.empty()) props["tableName"] = n->tableName;
|
||||
}
|
||||
else if (ct == "UpdateStatement") {
|
||||
auto* n = static_cast<const UpdateStatement*>(node);
|
||||
if (!n->tableName.empty()) props["tableName"] = n->tableName;
|
||||
}
|
||||
else if (ct == "DeleteStatement") {
|
||||
auto* n = static_cast<const DeleteStatement*>(node);
|
||||
if (!n->tableName.empty()) props["tableName"] = n->tableName;
|
||||
}
|
||||
else if (ct == "JoinClause") {
|
||||
auto* n = static_cast<const JoinClause*>(node);
|
||||
if (!n->joinType.empty()) props["joinType"] = n->joinType;
|
||||
if (!n->tableName.empty()) props["tableName"] = n->tableName;
|
||||
}
|
||||
else if (ct == "WhereClause") {
|
||||
auto* n = static_cast<const WhereClause*>(node);
|
||||
if (!n->expression.empty()) props["expression"] = n->expression;
|
||||
}
|
||||
else if (ct == "IndexDefinition") {
|
||||
auto* n = static_cast<const IndexDefinition*>(node);
|
||||
if (!n->name.empty()) props["name"] = n->name;
|
||||
if (!n->tableName.empty()) props["tableName"] = n->tableName;
|
||||
if (n->unique) props["unique"] = n->unique;
|
||||
}
|
||||
// NullLiteral, ListLiteral, IndexAccess, Block, Assignment, IfStatement,
|
||||
// WhileLoop, Return, ExpressionStatement, ListType, SetType, MapType,
|
||||
// TupleType, ArrayType, OptionalType — no extra properties
|
||||
@@ -716,6 +761,15 @@ inline ASTNode* createNode(const std::string& conceptName) {
|
||||
if (conceptName == "EnumMember") return new EnumMember();
|
||||
if (conceptName == "NamespaceDeclaration") return new NamespaceDeclaration();
|
||||
if (conceptName == "TypeAlias") return new TypeAlias();
|
||||
if (conceptName == "TableDeclaration") return new TableDeclaration();
|
||||
if (conceptName == "ColumnDefinition") return new ColumnDefinition();
|
||||
if (conceptName == "SelectQuery") return new SelectQuery();
|
||||
if (conceptName == "InsertStatement") return new InsertStatement();
|
||||
if (conceptName == "UpdateStatement") return new UpdateStatement();
|
||||
if (conceptName == "DeleteStatement") return new DeleteStatement();
|
||||
if (conceptName == "JoinClause") return new JoinClause();
|
||||
if (conceptName == "WhereClause") return new WhereClause();
|
||||
if (conceptName == "IndexDefinition") return new IndexDefinition();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1279,6 +1333,50 @@ inline void setPropertiesFromJson(ASTNode* node, const json& props) {
|
||||
if (props.contains("targetType")) n->targetType = props["targetType"].get<std::string>();
|
||||
if (props.contains("isUsing")) n->isUsing = props["isUsing"].get<bool>();
|
||||
}
|
||||
// SQL nodes (Step 410)
|
||||
else if (ct == "TableDeclaration") {
|
||||
auto* n = static_cast<TableDeclaration*>(node);
|
||||
if (props.contains("name")) n->name = props["name"].get<std::string>();
|
||||
if (props.contains("schema")) n->schema = props["schema"].get<std::string>();
|
||||
}
|
||||
else if (ct == "ColumnDefinition") {
|
||||
auto* n = static_cast<ColumnDefinition*>(node);
|
||||
if (props.contains("name")) n->name = props["name"].get<std::string>();
|
||||
if (props.contains("dataType")) n->dataType = props["dataType"].get<std::string>();
|
||||
if (props.contains("nullable")) n->nullable = props["nullable"].get<bool>();
|
||||
if (props.contains("defaultValue")) n->defaultValue = props["defaultValue"].get<std::string>();
|
||||
}
|
||||
else if (ct == "SelectQuery") {
|
||||
auto* n = static_cast<SelectQuery*>(node);
|
||||
if (props.contains("distinct")) n->distinct = props["distinct"].get<bool>();
|
||||
}
|
||||
else if (ct == "InsertStatement") {
|
||||
auto* n = static_cast<InsertStatement*>(node);
|
||||
if (props.contains("tableName")) n->tableName = props["tableName"].get<std::string>();
|
||||
}
|
||||
else if (ct == "UpdateStatement") {
|
||||
auto* n = static_cast<UpdateStatement*>(node);
|
||||
if (props.contains("tableName")) n->tableName = props["tableName"].get<std::string>();
|
||||
}
|
||||
else if (ct == "DeleteStatement") {
|
||||
auto* n = static_cast<DeleteStatement*>(node);
|
||||
if (props.contains("tableName")) n->tableName = props["tableName"].get<std::string>();
|
||||
}
|
||||
else if (ct == "JoinClause") {
|
||||
auto* n = static_cast<JoinClause*>(node);
|
||||
if (props.contains("joinType")) n->joinType = props["joinType"].get<std::string>();
|
||||
if (props.contains("tableName")) n->tableName = props["tableName"].get<std::string>();
|
||||
}
|
||||
else if (ct == "WhereClause") {
|
||||
auto* n = static_cast<WhereClause*>(node);
|
||||
if (props.contains("expression")) n->expression = props["expression"].get<std::string>();
|
||||
}
|
||||
else if (ct == "IndexDefinition") {
|
||||
auto* n = static_cast<IndexDefinition*>(node);
|
||||
if (props.contains("name")) n->name = props["name"].get<std::string>();
|
||||
if (props.contains("tableName")) n->tableName = props["tableName"].get<std::string>();
|
||||
if (props.contains("unique")) n->unique = props["unique"].get<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string generateNodeId() {
|
||||
|
||||
112
editor/src/ast/SqlNodes.h
Normal file
112
editor/src/ast/SqlNodes.h
Normal file
@@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
|
||||
#include "ASTNode.h"
|
||||
#include <string>
|
||||
|
||||
// SQL-specific AST nodes (Step 410)
|
||||
|
||||
class TableDeclaration : public ASTNode {
|
||||
public:
|
||||
std::string name;
|
||||
std::string schema;
|
||||
TableDeclaration() { conceptType = "TableDeclaration"; }
|
||||
TableDeclaration(const std::string& id_, const std::string& n, const std::string& s = "")
|
||||
: name(n), schema(s) {
|
||||
id = id_;
|
||||
conceptType = "TableDeclaration";
|
||||
}
|
||||
// children: "columns" (ColumnDefinition), "indexes" (IndexDefinition)
|
||||
};
|
||||
|
||||
class ColumnDefinition : public ASTNode {
|
||||
public:
|
||||
std::string name;
|
||||
std::string dataType;
|
||||
bool nullable = true;
|
||||
std::string defaultValue;
|
||||
ColumnDefinition() { conceptType = "ColumnDefinition"; }
|
||||
ColumnDefinition(const std::string& id_, const std::string& n,
|
||||
const std::string& dt, bool isNullable = true)
|
||||
: name(n), dataType(dt), nullable(isNullable) {
|
||||
id = id_;
|
||||
conceptType = "ColumnDefinition";
|
||||
}
|
||||
};
|
||||
|
||||
class SelectQuery : public ASTNode {
|
||||
public:
|
||||
bool distinct = false;
|
||||
SelectQuery() { conceptType = "SelectQuery"; }
|
||||
// children: "columns", "from", "joins", "where"
|
||||
};
|
||||
|
||||
class InsertStatement : public ASTNode {
|
||||
public:
|
||||
std::string tableName;
|
||||
InsertStatement() { conceptType = "InsertStatement"; }
|
||||
InsertStatement(const std::string& id_, const std::string& table) : tableName(table) {
|
||||
id = id_;
|
||||
conceptType = "InsertStatement";
|
||||
}
|
||||
// children: "columns", "values"
|
||||
};
|
||||
|
||||
class UpdateStatement : public ASTNode {
|
||||
public:
|
||||
std::string tableName;
|
||||
UpdateStatement() { conceptType = "UpdateStatement"; }
|
||||
UpdateStatement(const std::string& id_, const std::string& table) : tableName(table) {
|
||||
id = id_;
|
||||
conceptType = "UpdateStatement";
|
||||
}
|
||||
// children: "set", "where"
|
||||
};
|
||||
|
||||
class DeleteStatement : public ASTNode {
|
||||
public:
|
||||
std::string tableName;
|
||||
DeleteStatement() { conceptType = "DeleteStatement"; }
|
||||
DeleteStatement(const std::string& id_, const std::string& table) : tableName(table) {
|
||||
id = id_;
|
||||
conceptType = "DeleteStatement";
|
||||
}
|
||||
// children: "where"
|
||||
};
|
||||
|
||||
class JoinClause : public ASTNode {
|
||||
public:
|
||||
std::string joinType; // INNER/LEFT/RIGHT/FULL
|
||||
std::string tableName;
|
||||
JoinClause() { conceptType = "JoinClause"; }
|
||||
JoinClause(const std::string& id_, const std::string& jt, const std::string& tn)
|
||||
: joinType(jt), tableName(tn) {
|
||||
id = id_;
|
||||
conceptType = "JoinClause";
|
||||
}
|
||||
// children: "on"
|
||||
};
|
||||
|
||||
class WhereClause : public ASTNode {
|
||||
public:
|
||||
std::string expression;
|
||||
WhereClause() { conceptType = "WhereClause"; }
|
||||
WhereClause(const std::string& id_, const std::string& expr) : expression(expr) {
|
||||
id = id_;
|
||||
conceptType = "WhereClause";
|
||||
}
|
||||
};
|
||||
|
||||
class IndexDefinition : public ASTNode {
|
||||
public:
|
||||
std::string name;
|
||||
std::string tableName;
|
||||
bool unique = false;
|
||||
IndexDefinition() { conceptType = "IndexDefinition"; }
|
||||
IndexDefinition(const std::string& id_, const std::string& n,
|
||||
const std::string& table, bool isUnique = false)
|
||||
: name(n), tableName(table), unique(isUnique) {
|
||||
id = id_;
|
||||
conceptType = "IndexDefinition";
|
||||
}
|
||||
// children: "columns"
|
||||
};
|
||||
202
editor/tests/step410_test.cpp
Normal file
202
editor/tests/step410_test.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
// Step 410: SQL AST Nodes (12 tests)
|
||||
// Tests construction + serialization roundtrip for SQL-specific node types.
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include "ast/SqlNodes.h"
|
||||
#include "ast/Serialization.h"
|
||||
#include "CompactAST.h"
|
||||
|
||||
int main() {
|
||||
int passed = 0;
|
||||
|
||||
// 1. TableDeclaration construction
|
||||
{
|
||||
auto* t = new TableDeclaration("t1", "users", "public");
|
||||
assert(t->conceptType == "TableDeclaration");
|
||||
assert(t->name == "users");
|
||||
assert(t->schema == "public");
|
||||
delete t;
|
||||
std::cout << "Test 1 PASSED: TableDeclaration construction\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// 2. ColumnDefinition construction
|
||||
{
|
||||
auto* c = new ColumnDefinition("c1", "id", "INTEGER", false);
|
||||
c->defaultValue = "0";
|
||||
assert(c->conceptType == "ColumnDefinition");
|
||||
assert(c->name == "id");
|
||||
assert(c->dataType == "INTEGER");
|
||||
assert(!c->nullable);
|
||||
assert(c->defaultValue == "0");
|
||||
delete c;
|
||||
std::cout << "Test 2 PASSED: ColumnDefinition construction\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// 3. SelectQuery + clauses children
|
||||
{
|
||||
auto* q = new SelectQuery();
|
||||
q->id = "q1";
|
||||
q->distinct = true;
|
||||
q->addChild("joins", new JoinClause("j1", "INNER", "orders"));
|
||||
q->setChild("where", new WhereClause("w1", "id > 10"));
|
||||
assert(q->distinct);
|
||||
assert(q->getChildren("joins").size() == 1);
|
||||
assert(q->getChild("where") != nullptr);
|
||||
delete q;
|
||||
std::cout << "Test 3 PASSED: SelectQuery with clauses\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// 4. InsertStatement construction
|
||||
{
|
||||
auto* ins = new InsertStatement("i1", "users");
|
||||
ins->addChild("columns", new ColumnDefinition("c2", "name", "TEXT"));
|
||||
assert(ins->conceptType == "InsertStatement");
|
||||
assert(ins->tableName == "users");
|
||||
assert(ins->getChildren("columns").size() == 1);
|
||||
delete ins;
|
||||
std::cout << "Test 4 PASSED: InsertStatement construction\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// 5. UpdateStatement construction
|
||||
{
|
||||
auto* up = new UpdateStatement("u1", "users");
|
||||
up->setChild("where", new WhereClause("w2", "id = 1"));
|
||||
assert(up->conceptType == "UpdateStatement");
|
||||
assert(up->tableName == "users");
|
||||
assert(up->getChild("where") != nullptr);
|
||||
delete up;
|
||||
std::cout << "Test 5 PASSED: UpdateStatement construction\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// 6. DeleteStatement construction
|
||||
{
|
||||
auto* del = new DeleteStatement("d1", "logs");
|
||||
del->setChild("where", new WhereClause("w3", "created_at < now()"));
|
||||
assert(del->conceptType == "DeleteStatement");
|
||||
assert(del->tableName == "logs");
|
||||
assert(del->getChild("where") != nullptr);
|
||||
delete del;
|
||||
std::cout << "Test 6 PASSED: DeleteStatement construction\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// 7. IndexDefinition construction
|
||||
{
|
||||
auto* idx = new IndexDefinition("x1", "idx_users_email", "users", true);
|
||||
idx->addChild("columns", new ColumnDefinition("c3", "email", "TEXT"));
|
||||
assert(idx->conceptType == "IndexDefinition");
|
||||
assert(idx->name == "idx_users_email");
|
||||
assert(idx->tableName == "users");
|
||||
assert(idx->unique);
|
||||
delete idx;
|
||||
std::cout << "Test 7 PASSED: IndexDefinition construction\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// 8. Table with columns + index JSON roundtrip
|
||||
{
|
||||
auto* t = new TableDeclaration("t2", "accounts", "public");
|
||||
t->addChild("columns", new ColumnDefinition("c4", "id", "BIGINT", false));
|
||||
t->addChild("columns", new ColumnDefinition("c5", "email", "TEXT", false));
|
||||
t->addChild("indexes", new IndexDefinition("x2", "idx_accounts_email", "accounts", true));
|
||||
json j = toJson(t);
|
||||
auto* r = fromJson(j);
|
||||
assert(r->conceptType == "TableDeclaration");
|
||||
auto* rt = static_cast<TableDeclaration*>(r);
|
||||
assert(rt->name == "accounts");
|
||||
assert(rt->getChildren("columns").size() == 2);
|
||||
assert(rt->getChildren("indexes").size() == 1);
|
||||
delete t;
|
||||
delete r;
|
||||
std::cout << "Test 8 PASSED: table JSON roundtrip\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// 9. SelectQuery JSON roundtrip
|
||||
{
|
||||
auto* q = new SelectQuery();
|
||||
q->id = "q2";
|
||||
q->distinct = true;
|
||||
q->addChild("joins", new JoinClause("j2", "LEFT", "profiles"));
|
||||
q->setChild("where", new WhereClause("w4", "active = true"));
|
||||
json j = toJson(q);
|
||||
auto* r = fromJson(j);
|
||||
assert(r->conceptType == "SelectQuery");
|
||||
auto* rq = static_cast<SelectQuery*>(r);
|
||||
assert(rq->distinct);
|
||||
assert(rq->getChildren("joins").size() == 1);
|
||||
assert(rq->getChild("where") != nullptr);
|
||||
delete q;
|
||||
delete r;
|
||||
std::cout << "Test 9 PASSED: select JSON roundtrip\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// 10. CompactAST names
|
||||
{
|
||||
auto* t = new TableDeclaration("t3", "sessions");
|
||||
auto* c = new ColumnDefinition("c6", "token", "TEXT");
|
||||
auto* q = new SelectQuery();
|
||||
q->id = "q3";
|
||||
auto* d = new DeleteStatement("d2", "sessions");
|
||||
auto* w = new WhereClause("w5", "expired = true");
|
||||
auto* x = new IndexDefinition("x3", "idx_sessions_token", "sessions");
|
||||
assert(getNodeName(t) == "sessions");
|
||||
assert(getNodeName(c) == "token");
|
||||
assert(getNodeName(q) == "select");
|
||||
assert(getNodeName(d) == "sessions");
|
||||
assert(getNodeName(w) == "where");
|
||||
assert(getNodeName(x) == "idx_sessions_token");
|
||||
delete t; delete c; delete q; delete d; delete w; delete x;
|
||||
std::cout << "Test 10 PASSED: CompactAST SQL names\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// 11. createNode dispatch for SQL concepts
|
||||
{
|
||||
ASTNode* t = createNode("TableDeclaration");
|
||||
ASTNode* c = createNode("ColumnDefinition");
|
||||
ASTNode* s = createNode("SelectQuery");
|
||||
ASTNode* i = createNode("InsertStatement");
|
||||
ASTNode* u = createNode("UpdateStatement");
|
||||
ASTNode* d = createNode("DeleteStatement");
|
||||
ASTNode* j = createNode("JoinClause");
|
||||
ASTNode* w = createNode("WhereClause");
|
||||
ASTNode* x = createNode("IndexDefinition");
|
||||
assert(t && c && s && i && u && d && j && w && x);
|
||||
delete t; delete c; delete s; delete i; delete u; delete d; delete j; delete w; delete x;
|
||||
std::cout << "Test 11 PASSED: createNode SQL dispatch\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// 12. Full query graph roundtrip
|
||||
{
|
||||
auto* q = new SelectQuery();
|
||||
q->id = "q4";
|
||||
q->addChild("columns", new ColumnDefinition("c7", "id", "INTEGER"));
|
||||
q->setChild("from", new TableDeclaration("t4", "users"));
|
||||
q->addChild("joins", new JoinClause("j3", "INNER", "orders"));
|
||||
q->setChild("where", new WhereClause("w6", "users.id = orders.user_id"));
|
||||
json j = toJson(q);
|
||||
auto* r = fromJson(j);
|
||||
assert(r->conceptType == "SelectQuery");
|
||||
assert(r->getChildren("columns").size() == 1);
|
||||
assert(r->getChild("from") != nullptr);
|
||||
assert(r->getChildren("joins").size() == 1);
|
||||
assert(r->getChild("where") != nullptr);
|
||||
delete q;
|
||||
delete r;
|
||||
std::cout << "Test 12 PASSED: full query graph roundtrip\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
std::cout << "\nResults: " << passed << "/12 tests passed\n";
|
||||
return (passed == 12) ? 0 : 1;
|
||||
}
|
||||
54
progress.md
54
progress.md
@@ -3861,6 +3861,60 @@ Semanno annotation behavior across all 3 .NET-targeted outputs.
|
||||
- `editor/src/MCPServer.h` (`1679` > `600`)
|
||||
- `editor/src/HeadlessAgentRPCHandler.h` (`2623` > `600`)
|
||||
|
||||
## Phase 17b: SQL Dialect Support
|
||||
|
||||
### Step 410: SQL AST Nodes
|
||||
**Status:** PASS (12/12 tests)
|
||||
|
||||
Added first-class SQL AST node types and wired JSON serialization/deserialization
|
||||
and compact-node naming support so SQL structures can participate in existing
|
||||
pipeline tooling.
|
||||
|
||||
**Files created:**
|
||||
- `editor/src/ast/SqlNodes.h` — SQL node definitions:
|
||||
- `TableDeclaration`
|
||||
- `ColumnDefinition`
|
||||
- `SelectQuery`
|
||||
- `InsertStatement`
|
||||
- `UpdateStatement`
|
||||
- `DeleteStatement`
|
||||
- `JoinClause`
|
||||
- `WhereClause`
|
||||
- `IndexDefinition`
|
||||
- `editor/tests/step410_test.cpp` — 12 tests covering:
|
||||
1. table construction
|
||||
2. column construction
|
||||
3. select query + clause children
|
||||
4. insert statement construction
|
||||
5. update statement construction
|
||||
6. delete statement construction
|
||||
7. index construction
|
||||
8. table+columns+index JSON roundtrip
|
||||
9. select query JSON roundtrip
|
||||
10. compact AST naming for SQL nodes
|
||||
11. `createNode` SQL concept dispatch
|
||||
12. full query graph roundtrip
|
||||
|
||||
**Files modified:**
|
||||
- `editor/src/ast/Serialization.h` — SQL node property serialization,
|
||||
`createNode` mapping, and deserialization
|
||||
- `editor/src/CompactAST.h` — SQL node name mapping in `getNodeName`
|
||||
- `editor/CMakeLists.txt` — `step410_test` target
|
||||
|
||||
**Verification run:**
|
||||
- `step410_test` — PASS (12/12) new step coverage
|
||||
- `step409_test` — PASS (8/8) regression coverage
|
||||
- `step408_test` — PASS (12/12) regression coverage
|
||||
|
||||
**Architecture gate check:**
|
||||
- `editor/src/ast/SqlNodes.h` within header-size limit (`112` <= `600`)
|
||||
- `editor/tests/step410_test.cpp` within test-file size guidance (`202` lines)
|
||||
- `editor/src/CompactAST.h` at header-size limit (`600` <= `600`)
|
||||
- Legacy oversized headers persist:
|
||||
- `editor/src/ast/Serialization.h` (`1427` > `600`)
|
||||
- `editor/src/MCPServer.h` (`1679` > `600`)
|
||||
- `editor/src/HeadlessAgentRPCHandler.h` (`2623` > `600`)
|
||||
|
||||
# Roadmap Planning — Sprints 12-25+
|
||||
|
||||
## Status: Planning Complete (Sprints 12-19 detailed, 20-25 in roadmap.md)
|
||||
|
||||
Reference in New Issue
Block a user