feat: add fromByte and encodeTableJoin to protocol
This commit is contained in:
1 parent
e9b06f45d3
commit
b1f9202082
1 file changed
+146
@@ -1115,3 +1115,149 @@ pub const JoinMode = enum(u8) {
|
|||||||
right = 2,
|
right = 2,
|
||||||
full = 3,
|
full = 3,
|
||||||
|
|
||||||
|
pub fn fromByte(b: u8) !JoinMode {
|
||||||
|
return std.meta.intToEnum(JoinMode, b) catch error.UnknownJoinMode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Wire request for a remote `table join`: which variant (`mode`), the two
|
||||||
|
/// tables and the fields they are joined on, and an optional `expr.zig`
|
||||||
|
/// predicate text for each side - the same `leftPred`/`rightPred` filter
|
||||||
|
/// `join.innerJoin` and its outer variants already take, evaluated exactly
|
||||||
|
/// like `table_select`'s `exprText` (empty selects every row on that side).
|
||||||
|
pub fn encodeTableJoin(
|
||||||
|
allocator: Allocator,
|
||||||
|
mode: JoinMode,
|
||||||
|
leftTable: []const u8,
|
||||||
|
leftField: []const u8,
|
||||||
|
rightTable: []const u8,
|
||||||
|
rightField: []const u8,
|
||||||
|
offset: u32,
|
||||||
|
limit: u32,
|
||||||
|
leftExprText: []const u8,
|
||||||
|
rightExprText: []const u8,
|
||||||
|
) ![]u8 {
|
||||||
|
var buf = std.ArrayList(u8).init(allocator);
|
||||||
|
errdefer buf.deinit();
|
||||||
|
const w = encode.ByteWriter.init(&buf);
|
||||||
|
try w.byte(@intFromEnum(mode));
|
||||||
|
try putLenPrefixed(w, leftTable);
|
||||||
|
try putLenPrefixed(w, leftField);
|
||||||
|
try putLenPrefixed(w, rightTable);
|
||||||
|
try putLenPrefixed(w, rightField);
|
||||||
|
try w.putU32(offset);
|
||||||
|
try w.putU32(limit);
|
||||||
|
try putLenPrefixed(w, leftExprText);
|
||||||
|
try w.slice(rightExprText);
|
||||||
|
return buf.toOwnedSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TableJoinArgs = struct {
|
||||||
|
mode: JoinMode,
|
||||||
|
leftTable: []const u8,
|
||||||
|
leftField: []const u8,
|
||||||
|
rightTable: []const u8,
|
||||||
|
rightField: []const u8,
|
||||||
|
offset: u32 = 0,
|
||||||
|
limit: u32 = 0,
|
||||||
|
leftExprText: []const u8,
|
||||||
|
rightExprText: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn decodeTableJoin(payload: []const u8) !TableJoinArgs {
|
||||||
|
var c = Cursor{ .data = payload };
|
||||||
|
const mode = try JoinMode.fromByte(try c.takeByte());
|
||||||
|
const leftTable = try c.takeLenPrefixed();
|
||||||
|
const leftField = try c.takeLenPrefixed();
|
||||||
|
const rightTable = try c.takeLenPrefixed();
|
||||||
|
const rightField = try c.takeLenPrefixed();
|
||||||
|
const offset = try c.takeU32();
|
||||||
|
const limit = try c.takeU32();
|
||||||
|
const leftExprText = try c.takeLenPrefixed();
|
||||||
|
const rightExprText = c.data[c.pos..];
|
||||||
|
return .{
|
||||||
|
.mode = mode,
|
||||||
|
.leftTable = leftTable,
|
||||||
|
.leftField = leftField,
|
||||||
|
.rightTable = rightTable,
|
||||||
|
.rightField = rightField,
|
||||||
|
.offset = offset,
|
||||||
|
.limit = limit,
|
||||||
|
.leftExprText = leftExprText,
|
||||||
|
.rightExprText = rightExprText,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// One row pair from any of `join.zig`'s four variants, flattened to a
|
||||||
|
/// single wire shape: `innerJoin` never leaves either side null,
|
||||||
|
/// `leftOuterJoin`/`rightOuterJoin` leave exactly one side nullable, and
|
||||||
|
/// `fullOuterJoin` allows either - rather than four near-identical wire
|
||||||
|
/// encodings, every variant's result is converted to this one shape before
|
||||||
|
/// `encodeJoinedRows`, and the CLI decides what "(nil)" means from which
|
||||||
|
/// `--left`/`--right`/`--full` flag it sent, exactly like the local `table
|
||||||
|
/// join` printer already does per `JoinMode`.
|
||||||
|
pub const JoinPair = struct { left: ?rowmod.Row, right: ?rowmod.Row };
|
||||||
|
|
||||||
|
fn putOptionalRow(allocator: Allocator, w: encode.ByteWriter, row: ?rowmod.Row) !void {
|
||||||
|
if (row) |*r| {
|
||||||
|
try w.byte(1);
|
||||||
|
const encoded = try r.encode(allocator);
|
||||||
|
defer allocator.free(encoded);
|
||||||
|
try putLenPrefixed(w, encoded);
|
||||||
|
} else {
|
||||||
|
try w.byte(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encodeJoinedRows(allocator: Allocator, pairs: []const JoinPair) ![]u8 {
|
||||||
|
var buf = std.ArrayList(u8).init(allocator);
|
||||||
|
errdefer buf.deinit();
|
||||||
|
const w = encode.ByteWriter.init(&buf);
|
||||||
|
try w.putU32(@intCast(pairs.len));
|
||||||
|
for (pairs) |p| {
|
||||||
|
try putOptionalRow(allocator, w, p.left);
|
||||||
|
try putOptionalRow(allocator, w, p.right);
|
||||||
|
}
|
||||||
|
return buf.toOwnedSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn takeOptionalRow(allocator: Allocator, c: *Cursor) !?rowmod.Row {
|
||||||
|
const present = try c.takeByte();
|
||||||
|
if (present == 0) return null;
|
||||||
|
const raw = try c.takeLenPrefixed();
|
||||||
|
return rowmod.Row.decode(allocator, raw) catch return error.Malformed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes a `table_join` result set into independently owned `JoinPair`s -
|
||||||
|
/// callers must free each present side with `Row.deinit` (see
|
||||||
|
/// `freeJoinPairs` below).
|
||||||
|
pub fn decodeJoinedRows(allocator: Allocator, payload: []const u8) ![]JoinPair {
|
||||||
|
var c = Cursor{ .data = payload };
|
||||||
|
const count = try c.takeU32();
|
||||||
|
var list = try std.ArrayList(JoinPair).initCapacity(allocator, count);
|
||||||
|
errdefer {
|
||||||
|
for (list.items) |*p| {
|
||||||
|
if (p.left) |*l| l.deinit();
|
||||||
|
if (p.right) |*r| r.deinit();
|
||||||
|
}
|
||||||
|
list.deinit();
|
||||||
|
}
|
||||||
|
var i: u32 = 0;
|
||||||
|
while (i < count) : (i += 1) {
|
||||||
|
const left = try takeOptionalRow(allocator, &c);
|
||||||
|
const right = try takeOptionalRow(allocator, &c);
|
||||||
|
list.appendAssumeCapacity(.{ .left = left, .right = right });
|
||||||
|
}
|
||||||
|
return list.toOwnedSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn freeJoinPairs(allocator: Allocator, pairs: []JoinPair) void {
|
||||||
|
for (pairs) |*p| {
|
||||||
|
if (p.left) |*l| l.deinit();
|
||||||
|
if (p.right) |*r| r.deinit();
|
||||||
|
}
|
||||||
|
allocator.free(pairs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- table aggregate ---
|
||||||
|
|
||||||
Reference in new issue
Block a user