feat: fill in server
This commit is contained in:
1 parent
28fa271324
commit
d83f4f9ad1
1 file changed
+160
+160
@@ -3901,3 +3901,163 @@ test "server table_aggregate groups remote rows by field with count/sum, matchin
|
||||
const groups = try client.tableAggregateGroups(allocator, "orders", "city", &specs, 0, 0, &.{}, "", "");
|
||||
defer protocol.freeAggGroupRows(allocator, groups);
|
||||
|
||||
try std.testing.expectEqual(@as(usize, 2), groups.len);
|
||||
try std.testing.expectEqualStrings("warsaw", groups[0].group.text);
|
||||
try std.testing.expectEqual(@as(i64, 2), groups[0].values[0].int);
|
||||
try std.testing.expectEqual(@as(i64, 350), groups[0].values[1].int);
|
||||
try std.testing.expectEqualStrings("krakow", groups[1].group.text);
|
||||
try std.testing.expectEqual(@as(i64, 1), groups[1].values[0].int);
|
||||
try std.testing.expectEqual(@as(i64, 40), groups[1].values[1].int);
|
||||
}
|
||||
|
||||
test "server table_aggregate honors offset/limit to window the result groups server-side" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const path = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(path);
|
||||
|
||||
var db = try testDb(allocator, path);
|
||||
defer db.close();
|
||||
try seedAggregateOrders(allocator, &db);
|
||||
var orders = try querymod.Table.open(&db, allocator, "orders");
|
||||
try orders.put(.{ .int = 4 }, &.{
|
||||
.{ .name = "city", .value = .{ .text = "gdansk" } },
|
||||
.{ .name = "total", .value = .{ .int = 5 } },
|
||||
});
|
||||
orders.deinit();
|
||||
|
||||
const address = try std.net.Address.parseIp("127.0.0.1", 0);
|
||||
var server = try Server.init(allocator, &db, address);
|
||||
try server.start();
|
||||
defer server.stop();
|
||||
|
||||
const client_mod = @import("client.zig");
|
||||
var client = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer client.close();
|
||||
|
||||
const specs = [_]aggregatemod.AggSpec{.{ .field = "", .kind = .count }};
|
||||
|
||||
// Unpaged baseline: 3 distinct cities in first-seen order (warsaw twice
|
||||
// seeded first, then krakow, then gdansk added above).
|
||||
const all = try client.tableAggregateGroups(allocator, "orders", "city", &specs, 0, 0, &.{}, "", "");
|
||||
defer protocol.freeAggGroupRows(allocator, all);
|
||||
try std.testing.expectEqual(@as(usize, 3), all.len);
|
||||
|
||||
const paged = try client.tableAggregateGroups(allocator, "orders", "city", &specs, 1, 1, &.{}, "", "");
|
||||
defer protocol.freeAggGroupRows(allocator, paged);
|
||||
try std.testing.expectEqual(@as(usize, 1), paged.len);
|
||||
try std.testing.expectEqualStrings(all[1].group.text, paged[0].group.text);
|
||||
}
|
||||
|
||||
test "server table_aggregate with no groupField runs a single global aggregate and honors the expr filter" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const path = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(path);
|
||||
|
||||
var db = try testDb(allocator, path);
|
||||
defer db.close();
|
||||
try seedAggregateOrders(allocator, &db);
|
||||
|
||||
const address = try std.net.Address.parseIp("127.0.0.1", 0);
|
||||
var server = try Server.init(allocator, &db, address);
|
||||
try server.start();
|
||||
defer server.stop();
|
||||
|
||||
const client_mod = @import("client.zig");
|
||||
var client = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer client.close();
|
||||
|
||||
const specs = [_]aggregatemod.AggSpec{
|
||||
.{ .field = "", .kind = .count },
|
||||
.{ .field = "total", .kind = .sum },
|
||||
};
|
||||
const all = try client.tableAggregateGlobal(allocator, "orders", &specs, "", "");
|
||||
defer protocol.freeAggValues(allocator, all);
|
||||
try std.testing.expectEqual(@as(i64, 3), all[0].int);
|
||||
try std.testing.expectEqual(@as(i64, 390), all[1].int);
|
||||
|
||||
const filtered = try client.tableAggregateGlobal(allocator, "orders", &specs, "", "total gt i:50");
|
||||
defer protocol.freeAggValues(allocator, filtered);
|
||||
try std.testing.expectEqual(@as(i64, 2), filtered[0].int);
|
||||
try std.testing.expectEqual(@as(i64, 350), filtered[1].int);
|
||||
}
|
||||
|
||||
test "server table_aggregate applies a HAVING clause to result groups after aggregation, over real TCP" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const path = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(path);
|
||||
|
||||
var db = try testDb(allocator, path);
|
||||
defer db.close();
|
||||
try seedAggregateOrders(allocator, &db); // warsaw: count=2 sum=350, krakow: count=1 sum=40
|
||||
|
||||
const address = try std.net.Address.parseIp("127.0.0.1", 0);
|
||||
var server = try Server.init(allocator, &db, address);
|
||||
try server.start();
|
||||
defer server.stop();
|
||||
|
||||
const client_mod = @import("client.zig");
|
||||
var client = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer client.close();
|
||||
|
||||
const specs = [_]aggregatemod.AggSpec{
|
||||
.{ .field = "", .kind = .count },
|
||||
.{ .field = "total", .kind = .sum },
|
||||
};
|
||||
|
||||
// Referencing the printed aggregate label (sum_total): only warsaw's
|
||||
// group sum clears 100.
|
||||
const bySum = try client.tableAggregateGroups(allocator, "orders", "city", &specs, 0, 0, &.{}, "sum_total gt i:100", "");
|
||||
defer protocol.freeAggGroupRows(allocator, bySum);
|
||||
try std.testing.expectEqual(@as(usize, 1), bySum.len);
|
||||
try std.testing.expectEqualStrings("warsaw", bySum[0].group.text);
|
||||
|
||||
// Referencing the group key itself (city), not just an aggregate result.
|
||||
const byGroup = try client.tableAggregateGroups(allocator, "orders", "city", &specs, 0, 0, &.{}, "city eq s:krakow", "");
|
||||
defer protocol.freeAggGroupRows(allocator, byGroup);
|
||||
try std.testing.expectEqual(@as(usize, 1), byGroup.len);
|
||||
try std.testing.expectEqualStrings("krakow", byGroup[0].group.text);
|
||||
|
||||
// A HAVING clause that excludes every group comes back as zero groups,
|
||||
// not an error.
|
||||
const none = try client.tableAggregateGroups(allocator, "orders", "city", &specs, 0, 0, &.{}, "count gt i:1000", "");
|
||||
defer protocol.freeAggGroupRows(allocator, none);
|
||||
try std.testing.expectEqual(@as(usize, 0), none.len);
|
||||
}
|
||||
|
||||
test "server table_aggregate HAVING narrows groups before LIMIT/OFFSET windows them, over real TCP" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const path = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(path);
|
||||
|
||||
var db = try testDb(allocator, path);
|
||||
defer db.close();
|
||||
try seedAggregateOrders(allocator, &db);
|
||||
var orders = try querymod.Table.open(&db, allocator, "orders");
|
||||
try orders.put(.{ .int = 4 }, &.{
|
||||
.{ .name = "city", .value = .{ .text = "gdansk" } },
|
||||
.{ .name = "total", .value = .{ .int = 500 } },
|
||||
});
|
||||
orders.deinit();
|
||||
// Groups in first-seen order: warsaw(count=2 sum=350), krakow(count=1
|
||||
// sum=40), gdansk(count=1 sum=500). HAVING count gt 0 keeps all three,
|
||||
// but HAVING sum_total gt i:100 keeps only warsaw and gdansk (in that
|
||||
// order) - a limit of 1 must then return warsaw, not krakow (which
|
||||
// would be first if the window applied before HAVING).
|
||||
|
||||
const address = try std.net.Address.parseIp("127.0.0.1", 0);
|
||||
var server = try Server.init(allocator, &db, address);
|
||||
try server.start();
|
||||
defer server.stop();
|
||||
|
||||
const client_mod = @import("client.zig");
|
||||
var client = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer client.close();
|
||||
|
||||
Reference in new issue
Block a user