fix(query,types): refactor Row to Value-typed map, fix IN list, nkPath, multi-table joins
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
- Refactored Row from Table[string, string] to Table[string, Value] - Added Value operators: ==, !=, $, in for string interop - Fixed valueToString for vkNull to return '\\N' instead of '' - Fixed evalExpr irekField to return vkNull when field not found - Added IN (val1, val2, ...) parser support - Fixed nkPath column names in multi-table joins - Fixed LATERAL JOIN null padding when no matching rows - Added CREATE/DROP/USE/SHOW DATABASE parser support - Adapted all tests for new Value type
This commit is contained in:
Executable
BIN
Binary file not shown.
+12
-11
@@ -3,6 +3,7 @@ import std/strutils
|
||||
import std/os
|
||||
import std/tables
|
||||
import ../src/barabadb/query/[parser, executor, lexer, ast]
|
||||
import ../src/barabadb/core/types
|
||||
import ../src/barabadb/storage/lsm
|
||||
|
||||
const testDir = "/tmp/baradb_bugfix_test"
|
||||
@@ -73,7 +74,7 @@ suite "Bug fixes — IN list, nkPath exprToSql, multi-table joins":
|
||||
check r.success
|
||||
check r.rows.len == 1
|
||||
# Column is "t.id" (qualified by alias)
|
||||
check r.rows[0]["t.id"] == "42"
|
||||
check valueToString(r.rows[0]["t.id"]) == "42"
|
||||
|
||||
test "IN (list) executes with actual data":
|
||||
var ctx = setupCtx()
|
||||
@@ -123,9 +124,9 @@ suite "Bug fixes — IN list, nkPath exprToSql, multi-table joins":
|
||||
check r.success
|
||||
check r.rows.len == 1
|
||||
# Verify qualified column references resolve correctly
|
||||
check r.rows[0]["post.id"] == "100"
|
||||
check r.rows[0]["users.name"] == "Alice"
|
||||
check r.rows[0]["post.thread"] == "5"
|
||||
check valueToString(r.rows[0]["post.id"]) == "100"
|
||||
check valueToString(r.rows[0]["users.name"]) == "Alice"
|
||||
check valueToString(r.rows[0]["post.thread"]) == "5"
|
||||
# Check column names don't contain "nkPath"
|
||||
for col in r.columns:
|
||||
check not col.contains("nkPath")
|
||||
@@ -178,10 +179,10 @@ suite "Bug fixes — IN list, nkPath exprToSql, multi-table joins":
|
||||
check r.rows.len == 4
|
||||
# After sorting by name ASC, then id DESC within same name:
|
||||
# alice(3), alice(1), bob(2), charlie(4)
|
||||
check r.rows[0]["id"] == "3"
|
||||
check r.rows[1]["id"] == "1"
|
||||
check r.rows[2]["id"] == "2"
|
||||
check r.rows[3]["id"] == "4"
|
||||
check valueToString(r.rows[0]["id"]) == "3"
|
||||
check valueToString(r.rows[1]["id"]) == "1"
|
||||
check valueToString(r.rows[2]["id"]) == "2"
|
||||
check valueToString(r.rows[3]["id"]) == "4"
|
||||
|
||||
test "Numeric != comparison is consistent with =":
|
||||
var ctx = setupCtx()
|
||||
@@ -203,7 +204,7 @@ suite "Bug fixes — IN list, nkPath exprToSql, multi-table joins":
|
||||
# Column names should match the full path "posts.id", "posts.title"
|
||||
check r.columns == @["posts.id", "posts.title"]
|
||||
# Data should be accessible via both qualified and unqualified names
|
||||
check r.rows[0]["posts.id"] == "1"
|
||||
check valueToString(r.rows[0]["posts.id"]) == "1"
|
||||
|
||||
test "DELETE inside transaction actually removes row":
|
||||
var ctx = setupCtx()
|
||||
@@ -244,8 +245,8 @@ suite "Bug fixes — IN list, nkPath exprToSql, multi-table joins":
|
||||
let rmin = executeQuery(ctx, parse("SELECT MIN(val) AS m FROM scores"))
|
||||
check rmin.success
|
||||
check rmin.rows.len == 1
|
||||
check rmin.rows[0]["m"] == "10"
|
||||
check valueToString(rmin.rows[0]["m"]) == "10"
|
||||
let rmax = executeQuery(ctx, parse("SELECT MAX(val) AS m FROM scores"))
|
||||
check rmax.success
|
||||
check rmax.rows.len == 1
|
||||
check rmax.rows[0]["m"] == "30"
|
||||
check valueToString(rmax.rows[0]["m"]) == "30"
|
||||
|
||||
@@ -3,6 +3,8 @@ import std/os
|
||||
import std/strutils
|
||||
import std/monotimes
|
||||
import std/tables
|
||||
import std/sequtils
|
||||
import barabadb/core/types
|
||||
import barabadb/query/executor as qexec
|
||||
import barabadb/query/parser
|
||||
import barabadb/storage/lsm
|
||||
@@ -97,7 +99,7 @@ suite "JOIN execution":
|
||||
var foundBob = false
|
||||
for row in r.rows:
|
||||
if row["u.name"] == "Bob":
|
||||
check row["x.total"] == "\\N"
|
||||
check row["x.total"].kind == vkNull
|
||||
foundBob = true
|
||||
check foundBob
|
||||
|
||||
|
||||
+14
-14
@@ -2831,7 +2831,7 @@ suite "Window Functions":
|
||||
# Sales: Diana(75000)=1, Charlie(70000)=2
|
||||
var found = initTable[string, string]()
|
||||
for row in r.rows:
|
||||
found[row["name"]] = row["rn"]
|
||||
found[$row["name"]] = $row["rn"]
|
||||
check found["Eve"] == "1"
|
||||
check found["Alice"] == "2"
|
||||
check found["Bob"] == "3"
|
||||
@@ -3474,7 +3474,7 @@ suite "Auto-Increment & ID Generators":
|
||||
let r = qexec.executeQuery(ctx, parse("SELECT gen_random_uuid() AS uid"))
|
||||
check r.success
|
||||
check r.rows.len == 1
|
||||
let uid = r.rows[0]["uid"]
|
||||
let uid = $r.rows[0]["uid"]
|
||||
check uid.len == 36
|
||||
check uid[8] == '-'
|
||||
check uid[13] == '-'
|
||||
@@ -3486,7 +3486,7 @@ suite "Auto-Increment & ID Generators":
|
||||
let r = qexec.executeQuery(ctx, parse("SELECT uuid() AS uid"))
|
||||
check r.success
|
||||
check r.rows.len == 1
|
||||
check r.rows[0]["uid"].len == 36
|
||||
check ($r.rows[0]["uid"]).len == 36
|
||||
|
||||
test "Two UUIDs are different":
|
||||
let r = qexec.executeQuery(ctx, parse("SELECT uuid() AS a, uuid() AS b"))
|
||||
@@ -3564,7 +3564,7 @@ suite "Auto-Increment & ID Generators":
|
||||
let r = qexec.executeQuery(ctx, parse("SELECT snowflake_id(1) AS sid"))
|
||||
check r.success
|
||||
check r.rows.len == 1
|
||||
let sid = r.rows[0]["sid"]
|
||||
let sid = $r.rows[0]["sid"]
|
||||
check sid.len > 0
|
||||
var num: int64 = 0
|
||||
try:
|
||||
@@ -3720,17 +3720,17 @@ suite "Type Safety — evalExprValue":
|
||||
check r.success
|
||||
check r.rows[0]["r"] == "17.5"
|
||||
|
||||
test "evalExprValue returns correct Value kind for literals":
|
||||
test "evalExpr returns correct Value kind for literals":
|
||||
let lit = IRExpr(kind: irekLiteral, valueKind: vkInt64)
|
||||
lit.literal = IRLiteral(kind: vkInt64, int64Val: 42)
|
||||
let v = evalExprValue(lit, initTable[string, string](), nil)
|
||||
let v = evalExpr(lit, initTable[string, Value](), nil)
|
||||
check v.kind == vkInt64
|
||||
check v.int64Val == 42
|
||||
|
||||
test "evalExprValue returns correct Value kind for float literal":
|
||||
test "evalExpr returns correct Value kind for float literal":
|
||||
let lit = IRExpr(kind: irekLiteral, valueKind: vkFloat64)
|
||||
lit.literal = IRLiteral(kind: vkFloat64, float64Val: 3.14)
|
||||
let v = evalExprValue(lit, initTable[string, string](), nil)
|
||||
let v = evalExpr(lit, initTable[string, Value](), nil)
|
||||
check v.kind == vkFloat64
|
||||
check v.float64Val == 3.14
|
||||
|
||||
@@ -3998,7 +3998,7 @@ suite "Hybrid RAG Search":
|
||||
let r = qexec.executeQuery(ctx, parse("SELECT hybrid_search('docs', 'embedding', 'content', 'quick brown', '[1.0, 0.0, 0.0]', 10) AS res"))
|
||||
check r.success
|
||||
check r.rows.len == 1
|
||||
let jsonStr = r.rows[0]["res"]
|
||||
let jsonStr = $r.rows[0]["res"]
|
||||
check jsonStr.len > 2 # not "[]"
|
||||
let arr = parseJson(jsonStr)
|
||||
check arr.kind == JArray
|
||||
@@ -4013,7 +4013,7 @@ suite "Hybrid RAG Search":
|
||||
let r = qexec.executeQuery(ctx, parse("SELECT hybrid_search_ids('docs2', 'embedding', 'content', 'machine learning', '[0.0, 1.0, 0.0]', 10) AS ids"))
|
||||
check r.success
|
||||
check r.rows.len == 1
|
||||
let idsStr = r.rows[0]["ids"]
|
||||
let idsStr = $r.rows[0]["ids"]
|
||||
check idsStr.len > 0
|
||||
check idsStr.contains("20")
|
||||
|
||||
@@ -4029,7 +4029,7 @@ suite "Hybrid RAG Search":
|
||||
discard qexec.executeQuery(ctx, parse("CREATE INDEX idx_fts3 ON docs3(content) USING FTS"))
|
||||
let r = qexec.executeQuery(ctx, parse("SELECT hybrid_search('docs3', 'embedding', 'content', 'quick brown fox', '[1.0, 0.0, 0.0]', 10) AS res"))
|
||||
check r.success
|
||||
let arr = parseJson(r.rows[0]["res"])
|
||||
let arr = parseJson($r.rows[0]["res"])
|
||||
check arr.len == 3
|
||||
# Doc 3 should be first (matches both vector and FTS), doc 1 second (vector only), doc 2 third (no match)
|
||||
check arr[0]["id"].getStr() == "3"
|
||||
@@ -4038,7 +4038,7 @@ suite "Hybrid RAG Search":
|
||||
let r = qexec.executeQuery(ctx, parse("SELECT rerank('quick brown', '[{\"id\":\"1\",\"score\":\"0.5\"},{\"id\":\"2\",\"score\":\"0.5\"}]') AS res"))
|
||||
check r.success
|
||||
# Both have same score, rerank should preserve order (no content to boost)
|
||||
let arr = parseJson(r.rows[0]["res"])
|
||||
let arr = parseJson($r.rows[0]["res"])
|
||||
check arr.kind == JArray
|
||||
check arr.len == 2
|
||||
|
||||
@@ -4060,7 +4060,7 @@ suite "Hybrid RAG Search":
|
||||
discard qexec.executeQuery(ctx, parse("CREATE INDEX idx_fts5 ON docs5(content) USING FTS"))
|
||||
let r = qexec.executeQuery(ctx, parse("SELECT hybrid_search_filtered('docs5', 'embedding', 'content', 'quick brown fox', '[1.0, 0.0, 0.0]', 10, 'tenant_id', 'tenant-a') AS res"))
|
||||
check r.success
|
||||
let arr = parseJson(r.rows[0]["res"])
|
||||
let arr = parseJson($r.rows[0]["res"])
|
||||
# Doc 1 (tenant-a) should be first and highest scored; Doc 2 (tenant-b) must be excluded
|
||||
check arr[0]["id"].getStr() == "1"
|
||||
for elem in arr:
|
||||
@@ -4074,6 +4074,6 @@ suite "Hybrid RAG Search":
|
||||
discard qexec.executeQuery(ctx, parse("CREATE INDEX idx_fts6 ON docs6(content) USING FTS"))
|
||||
let r = qexec.executeQuery(ctx, parse("SELECT hybrid_search_filtered('docs6', 'embedding', 'content', 'quick brown fox', '[1.0, 0.0, 0.0]', 10, '', '') AS res"))
|
||||
check r.success
|
||||
let arr = parseJson(r.rows[0]["res"])
|
||||
let arr = parseJson($r.rows[0]["res"])
|
||||
check arr.len == 2
|
||||
|
||||
|
||||
Reference in New Issue
Block a user