feat: extend server
This commit is contained in:
1 parent
d83f4f9ad1
commit
097f1ca9fc
1 file changed
+158
+158
@@ -4061,3 +4061,161 @@ test "server table_aggregate HAVING narrows groups before LIMIT/OFFSET windows t
|
||||
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 paged = try client.tableAggregateGroups(allocator, "orders", "city", &specs, 0, 1, &.{}, "sum_total gt i:100", "");
|
||||
defer protocol.freeAggGroupRows(allocator, paged);
|
||||
try std.testing.expectEqual(@as(usize, 1), paged.len);
|
||||
try std.testing.expectEqualStrings("warsaw", paged[0].group.text);
|
||||
|
||||
const pagedOffset = try client.tableAggregateGroups(allocator, "orders", "city", &specs, 1, 1, &.{}, "sum_total gt i:100", "");
|
||||
defer protocol.freeAggGroupRows(allocator, pagedOffset);
|
||||
try std.testing.expectEqual(@as(usize, 1), pagedOffset.len);
|
||||
try std.testing.expectEqualStrings("gdansk", pagedOffset[0].group.text);
|
||||
}
|
||||
|
||||
test "server table_aggregate HAVING on the global (no groupField) path excludes the single row without erroring, 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); // global: count=3 sum=390
|
||||
|
||||
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 passing = try client.tableAggregateGlobal(allocator, "orders", &specs, "sum_total gt i:100", "");
|
||||
defer protocol.freeAggValues(allocator, passing);
|
||||
try std.testing.expectEqual(@as(usize, 2), passing.len);
|
||||
try std.testing.expectEqual(@as(i64, 390), passing[1].int);
|
||||
|
||||
const excluded = try client.tableAggregateGlobal(allocator, "orders", &specs, "sum_total gt i:100000", "");
|
||||
defer protocol.freeAggValues(allocator, excluded);
|
||||
try std.testing.expectEqual(@as(usize, 0), excluded.len);
|
||||
}
|
||||
|
||||
test "server table_aggregate reports a malformed HAVING expr as bad_request, not a crash" {
|
||||
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 }};
|
||||
const err = client.tableAggregateGroups(allocator, "orders", "city", &specs, 0, 0, &.{}, "count bogus i:1", "");
|
||||
try std.testing.expectError(client_mod.ClientError.ServerBadRequest, err);
|
||||
}
|
||||
|
||||
test "server table_aggregate count_distinct collapses repeated field values, locally and globally, 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();
|
||||
{
|
||||
var orders = try querymod.Table.open(&db, allocator, "orders");
|
||||
defer orders.deinit();
|
||||
// Both warsaw rows share the same region on purpose - the whole
|
||||
// point of this test is that COUNT(DISTINCT region) collapses them
|
||||
// to 1, unlike plain COUNT which would report 2.
|
||||
try orders.put(.{ .int = 1 }, &.{
|
||||
.{ .name = "city", .value = .{ .text = "warsaw" } },
|
||||
.{ .name = "region", .value = .{ .text = "mazovia" } },
|
||||
});
|
||||
try orders.put(.{ .int = 2 }, &.{
|
||||
.{ .name = "city", .value = .{ .text = "warsaw" } },
|
||||
.{ .name = "region", .value = .{ .text = "mazovia" } },
|
||||
});
|
||||
try orders.put(.{ .int = 3 }, &.{
|
||||
.{ .name = "city", .value = .{ .text = "krakow" } },
|
||||
.{ .name = "region", .value = .{ .text = "malopolska" } },
|
||||
});
|
||||
}
|
||||
|
||||
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 = "region", .kind = .count_distinct },
|
||||
};
|
||||
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); // COUNT(*)
|
||||
try std.testing.expectEqual(@as(i64, 1), groups[0].values[1].int); // COUNT(DISTINCT region)
|
||||
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, 1), groups[1].values[1].int);
|
||||
|
||||
const globalSpecs = [_]aggregatemod.AggSpec{.{ .field = "region", .kind = .count_distinct }};
|
||||
const global = try client.tableAggregateGlobal(allocator, "orders", &globalSpecs, "", "");
|
||||
defer protocol.freeAggValues(allocator, global);
|
||||
try std.testing.expectEqual(@as(i64, 2), global[0].int); // mazovia + malopolska
|
||||
}
|
||||
|
||||
test "server table_aggregate reports a non-numeric sum field as bad_request, not a crash" {
|
||||
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 = "city", .kind = .sum }};
|
||||
const err = client.tableAggregateGlobal(allocator, "orders", &specs, "", "");
|
||||
try std.testing.expectError(client_mod.ClientError.ServerBadRequest, err);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user