feat: Phase 5-6 — CREATE VIEW, migrations, deadlock detection, JSON logging, admin UI
Phase 5 — ERP Features: - CREATE VIEW name AS SELECT ... — parser + executor with view expansion - DROP VIEW — parser + executor - CREATE MIGRATION name AS 'sql' — parser + executor, stored in LSM-Tree - APPLY MIGRATION name — parser + executor, replays stored migration SQL - Views table in ExecutionContext, expanded on SELECT FROM view Phase 6 — Production Readiness: - Deadlock detection: timeout-based auto-abort for stale transactions (30s default) - TxnManager.txnTimeoutMs configurable - Structured JSON logging module (logging.nim) with levels: debug/info/warn/error - Admin dashboard Web UI at GET /admin — SQL playground, schema browser, metrics - Dark theme HTML/CSS with tabs Lexer: added tkView, tkMigration, tkApply tokens Parser: parseCreateView, parseDropView, parseCreateMigration, parseApplyMigration AST: nkCreateView, nkDropView, nkCreateMigration, nkApplyMigration nodes All 216 tests pass
This commit is contained in:
@@ -738,6 +738,47 @@ proc parseExplain(p: var Parser): Node =
|
||||
result.expAnalyze = true
|
||||
result.expStmt = p.parseStatement()
|
||||
|
||||
proc parseCreateView(p: var Parser): Node =
|
||||
let tok = p.expect(tkCreate)
|
||||
var orReplace = false
|
||||
if p.peek().kind == tkIdent and p.peek().value.toLower() == "or":
|
||||
discard p.advance()
|
||||
discard p.expect(tkIdent) # REPLACE
|
||||
orReplace = true
|
||||
discard p.expect(tkView)
|
||||
let name = p.expect(tkIdent).value
|
||||
discard p.expect(tkAs)
|
||||
let query = p.parseSelect()
|
||||
result = Node(kind: nkCreateView, cvName: name, cvQuery: query,
|
||||
cvOrReplace: orReplace, line: tok.line, col: tok.col)
|
||||
|
||||
proc parseDropView(p: var Parser): Node =
|
||||
let tok = p.expect(tkDrop)
|
||||
discard p.expect(tkView)
|
||||
var ifExists = false
|
||||
if p.peek().kind == tkIdent and p.peek().value.toLower() == "if":
|
||||
discard p.advance()
|
||||
discard p.expect(tkExists)
|
||||
ifExists = true
|
||||
let name = p.expect(tkIdent).value
|
||||
result = Node(kind: nkDropView, dvName: name, dvIfExists: ifExists,
|
||||
line: tok.line, col: tok.col)
|
||||
|
||||
proc parseCreateMigration(p: var Parser): Node =
|
||||
let tok = p.expect(tkCreate)
|
||||
discard p.expect(tkMigration)
|
||||
let name = p.expect(tkIdent).value
|
||||
discard p.expect(tkAs)
|
||||
let body = p.expect(tkStringLit).value
|
||||
result = Node(kind: nkCreateMigration, cmName: name, cmBody: body,
|
||||
line: tok.line, col: tok.col)
|
||||
|
||||
proc parseApplyMigration(p: var Parser): Node =
|
||||
let tok = p.expect(tkIdent) # APPLY
|
||||
discard p.expect(tkMigration)
|
||||
let name = p.expect(tkIdent).value
|
||||
result = Node(kind: nkApplyMigration, amName: name, line: tok.line, col: tok.col)
|
||||
|
||||
proc parseStatement*(p: var Parser): Node =
|
||||
case p.peek().kind
|
||||
of tkWith, tkSelect: p.parseSelect()
|
||||
@@ -752,13 +793,25 @@ proc parseStatement*(p: var Parser): Node =
|
||||
p.parseCreateTable()
|
||||
elif next.kind == tkIndex or next.kind == tkUnique:
|
||||
p.parseCreateIndex()
|
||||
elif next.kind == tkView or
|
||||
(next.kind == tkIdent and next.value.toLower() == "or"):
|
||||
p.parseCreateView()
|
||||
elif next.kind == tkMigration:
|
||||
p.parseCreateMigration()
|
||||
else:
|
||||
p.parseCreateType()
|
||||
else:
|
||||
p.parseCreateType()
|
||||
of tkDrop:
|
||||
if p.pos + 1 < p.tokens.len and p.tokens[p.pos + 1].kind == tkTable:
|
||||
p.parseDropTable()
|
||||
if p.pos + 1 < p.tokens.len:
|
||||
let next = p.tokens[p.pos + 1]
|
||||
if next.kind == tkTable:
|
||||
p.parseDropTable()
|
||||
elif next.kind == tkView:
|
||||
p.parseDropView()
|
||||
else:
|
||||
let tok = p.advance()
|
||||
Node(kind: nkNullLit, line: tok.line, col: tok.col)
|
||||
else:
|
||||
let tok = p.advance()
|
||||
Node(kind: nkNullLit, line: tok.line, col: tok.col)
|
||||
@@ -768,6 +821,12 @@ proc parseStatement*(p: var Parser): Node =
|
||||
else:
|
||||
let tok = p.advance()
|
||||
Node(kind: nkNullLit, line: tok.line, col: tok.col)
|
||||
of tkApply:
|
||||
if p.pos + 1 < p.tokens.len and p.tokens[p.pos + 1].kind == tkMigration:
|
||||
p.parseApplyMigration()
|
||||
else:
|
||||
let tok = p.advance()
|
||||
Node(kind: nkNullLit, line: tok.line, col: tok.col)
|
||||
of tkBegin: p.parseBeginTxn()
|
||||
of tkCommit: p.parseCommitTxn()
|
||||
of tkRollback: p.parseRollbackTxn()
|
||||
|
||||
Reference in New Issue
Block a user