feat: expand repl

This commit is contained in:
dualfroz committed 2026-09-09 21:52:23 +02:00
1 parent b77a2c9641
commit 4ab4567114
1 file changed
+154
+154
View File
@@ -1577,3 +1577,157 @@ test "table select --order-by rejects an empty segment from a doubled comma inst
try std.testing.expectEqualStrings("OK\nerror: InvalidPageFlag\n", out);
}
test "table select reports a parse error on malformed expr without crashing" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
var db = try openTemp(&tmp, allocator);
defer db.close();
var repl = Repl.init(allocator, &db);
defer repl.deinit();
const out = try runScript(allocator, &repl, "table select items price bogus i:1\n");
defer allocator.free(out);
try std.testing.expectEqualStrings("error: UnknownOperator\n", out);
}
test "table explain reports full_scan, an index, and a composite index, matching what table select would actually use" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
var db = try openTemp(&tmp, allocator);
defer db.close();
{
var table = try Table.open(&db, allocator, "users");
defer table.deinit();
try table.createIndex("age");
try table.createCompositeIndex("city_age", &.{ "city", "age" });
}
var repl = Repl.init(allocator, &db);
defer repl.deinit();
const out = try runScript(allocator, &repl,
\\table put users i:1 city=s:warsaw age=i:30
\\table explain users
\\table explain users city eq s:warsaw
\\table explain users age eq i:30
\\table explain users city eq s:warsaw and age eq i:30
\\
);
defer allocator.free(out);
try std.testing.expectEqualStrings(
"OK\n" ++
"full scan (no usable index)\n" ++
"full scan (no usable index)\n" ++
"index 'age' (equality)\n" ++
"composite index 'city_age' (equality, 2/2 columns matched)\n",
out,
);
}
test "table update applies --set to matching rows, prints the count, and leaves other rows untouched" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
var db = try openTemp(&tmp, allocator);
defer db.close();
var repl = Repl.init(allocator, &db);
defer repl.deinit();
const out = try runScript(allocator, &repl,
\\table put users i:1 city=s:warsaw active=i:0
\\table put users i:2 city=s:warsaw active=i:0
\\table put users i:3 city=s:krakow active=i:0
\\table update users --set active=i:1 city eq s:warsaw
\\table select users --order-by __pk
\\
);
defer allocator.free(out);
try std.testing.expectEqualStrings(
"OK\nOK\nOK\n" ++
"2\n" ++
"__pk=1\tcity=warsaw\tactive=1\n" ++
"__pk=2\tcity=warsaw\tactive=1\n" ++
"__pk=3\tcity=krakow\tactive=0\n",
out,
);
}
test "table update without --set is rejected as MissingSetFlag instead of silently updating nothing" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
var db = try openTemp(&tmp, allocator);
defer db.close();
var repl = Repl.init(allocator, &db);
defer repl.deinit();
const out = try runScript(allocator, &repl, "table put users i:1 city=s:warsaw\ntable update users city eq s:warsaw\n");
defer allocator.free(out);
try std.testing.expectEqualStrings("OK\nerror: MissingSetFlag\n", out);
}
test "table join inner/left/right/full match main.zig's L/R printing" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
var db = try openTemp(&tmp, allocator);
defer db.close();
var repl = Repl.init(allocator, &db);
defer repl.deinit();
const out = try runScript(allocator, &repl,
\\table put customers i:1 name=alice
\\table put customers i:2 name=bob
\\table put orders i:100 customer_id=i:1 total=i:50
\\table put orders i:101 customer_id=i:999 total=i:5
\\table join customers __pk orders customer_id
\\table join --left customers __pk orders customer_id
\\table join --right customers __pk orders customer_id
\\table join --full customers __pk orders customer_id
\\
);
defer allocator.free(out);
try std.testing.expectEqualStrings(
// plain inner join: only alice/order100 matches, bob and the orphan
// order are absent.
"OK\nOK\nOK\nOK\n" ++
"L __pk=1\tname=alice\n" ++
"R __pk=100\tcustomer_id=1\ttotal=50\n" ++
// --left: bob survives with R (nil), the orphan order is still absent.
"L __pk=1\tname=alice\n" ++
"R __pk=100\tcustomer_id=1\ttotal=50\n" ++
"L __pk=2\tname=bob\n" ++
"R (nil)\n" ++
// --right: the orphan order survives with L (nil), bob is absent.
"L __pk=1\tname=alice\n" ++
"R __pk=100\tcustomer_id=1\ttotal=50\n" ++
"L (nil)\n" ++
"R __pk=101\tcustomer_id=999\ttotal=5\n" ++
// --full: both bob and the orphan order survive.
"L __pk=1\tname=alice\n" ++
"R __pk=100\tcustomer_id=1\ttotal=50\n" ++
"L __pk=2\tname=bob\n" ++
"R (nil)\n" ++
"L (nil)\n" ++
"R __pk=101\tcustomer_id=999\ttotal=5\n",
out,
);
}
test "table join respects --limit and --offset like table select does" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
var db = try openTemp(&tmp, allocator);
defer db.close();
var repl = Repl.init(allocator, &db);
defer repl.deinit();