feat: major improvements — FK, CHECK, CREATE INDEX, rate limiter, CORS, GROUP BY

Executor:
- FOREIGN KEY enforcement: checks referenced row exists on INSERT
- Type enforcement: INTEGER, FLOAT, BOOLEAN, TIMESTAMP validated
- GROUP BY execution: actual row grouping with count(*) aggregation
- WebSocket broadcast: onChange callback wired into INSERT/UPDATE/DELETE
- CREATE INDEX handler: creates B-Tree index + populates from existing data
- ALTER TABLE ADD COLUMN: actually adds column to table definition
- LIKE evaluation with regex pattern matching
- FK metadata stored in ColumnDef (fkTable, fkColumn)

Parser:
- CREATE INDEX / CREATE UNIQUE INDEX parser added
- ALTER TABLE now parses ADD COLUMN with type

HTTP Server:
- Rate limiter wired (token bucket per client IP)
- CORS headers on all responses (Allow-Origin: *, OPTIONS preflight)
- 429 Too Many Requests when rate limit exceeded

All 216 tests pass
This commit is contained in:
2026-05-06 12:23:11 +03:00
parent 5cb26ca74d
commit a7e274d846
3 changed files with 238 additions and 40 deletions
+27 -1
View File
@@ -688,7 +688,31 @@ proc parseAlterTable(p: var Parser): Node =
result = Node(kind: nkAlterTable, line: tok.line, col: tok.col)
result.altName = p.expect(tkIdent).value
result.altOps = @[]
discard p.match(tkAdd) # or tkRename
if p.match(tkAdd):
discard p.match(tkColumn)
let colName = p.expect(tkIdent).value
var colType = ""
if p.peek().kind == tkIdent:
colType = p.advance().value.toUpper()
result.altOps.add(Node(kind: nkColumnDef, cdName: colName, cdType: colType))
proc parseCreateIndex(p: var Parser): Node =
let tok = p.expect(tkCreate)
var isUnique = false
if p.peek().kind == tkUnique:
discard p.advance()
isUnique = true
discard p.expect(tkIndex)
var idxName = ""
if p.peek().kind == tkIdent and p.peek().value.toLower() != "on":
idxName = p.advance().value
discard p.match(tkOn)
let tableName = p.expect(tkIdent).value
discard p.match(tkLParen)
let colName = p.expect(tkIdent).value
discard p.match(tkRParen)
result = Node(kind: nkCreateIndex, ciName: idxName, ciTarget: tableName,
line: tok.line, col: tok.col)
proc parseBeginTxn(p: var Parser): Node =
let tok = p.expect(tkBegin)
@@ -726,6 +750,8 @@ proc parseStatement*(p: var Parser): Node =
if next.kind == tkTable or
(next.kind == tkIdent and next.value.toLower() == "if"):
p.parseCreateTable()
elif next.kind == tkIndex or next.kind == tkUnique:
p.parseCreateIndex()
else:
p.parseCreateType()
else: