diff --git a/src/protocol.zig b/src/protocol.zig index 235d4c7..ff60c92 100644 --- a/src/protocol.zig +++ b/src/protocol.zig @@ -1570,3 +1570,150 @@ pub const TableWindowArgs = struct { exprText: []const u8, }; +pub fn decodeTableWindow(allocator: Allocator, payload: []const u8) !TableWindowArgs { + var c = Cursor{ .data = payload }; + const table = try c.takeLenPrefixed(); + const specCount = try c.takeByte(); + var specs = try std.ArrayList(windowmod.WindowSpec).initCapacity(allocator, specCount); + errdefer specs.deinit(); + var s: u8 = 0; + while (s < specCount) : (s += 1) { + const kindByte = try c.takeByte(); + const kind = std.meta.intToEnum(windowmod.WindowKind, kindByte) catch return error.Malformed; + const field = try c.takeLenPrefixed(); + if (kind == .lag or kind == .lead or kind == .nth_value) { + const extra = try takeLagLeadExtra(&c); + specs.appendAssumeCapacity(.{ .kind = kind, .field = field, .offset = extra.offset, .default = extra.default }); + } else { + specs.appendAssumeCapacity(.{ .kind = kind, .field = field }); + } + } + const partitionCount = try c.takeByte(); + var partitionBy = try std.ArrayList([]const u8).initCapacity(allocator, partitionCount); + errdefer partitionBy.deinit(); + var i: u8 = 0; + while (i < partitionCount) : (i += 1) partitionBy.appendAssumeCapacity(try c.takeLenPrefixed()); + const orderCount = try c.takeByte(); + var orderBy = try std.ArrayList(querymod.OrderBy).initCapacity(allocator, orderCount); + errdefer orderBy.deinit(); + var j: u8 = 0; + while (j < orderCount) : (j += 1) { + const descending = try c.takeByte(); + const obField = try c.takeLenPrefixed(); + orderBy.appendAssumeCapacity(.{ .field = obField, .descending = descending != 0 }); + } + const offset = try c.takeU32(); + const limit = try c.takeU32(); + const frameByte = try c.takeByte(); + const frame = std.meta.intToEnum(windowmod.FrameMode, frameByte) catch return error.Malformed; + const exprText = c.data[c.pos..]; + return .{ + .table = table, + .specs = try specs.toOwnedSlice(), + .partitionBy = try partitionBy.toOwnedSlice(), + .orderBy = try orderBy.toOwnedSlice(), + .offset = offset, + .limit = limit, + .frame = frame, + .exprText = exprText, + }; +} + +/// One annotated row from a `table_window` result: the original row +/// (unmodified, same fields the request matched) paired with one computed +/// window value PER requested spec, in the same order as the request's +/// `specs` list - the network shape of what local `table window` prints per +/// row (`printRow` fields, then `