feat: add TableDeleteArgs and decodeTableDelete to protocol
This commit is contained in:
1 parent
5d433ed37b
commit
d09dc6aaf0
1 file changed
+159
@@ -2036,3 +2036,162 @@ pub fn encodeTableDelete(allocator: Allocator, table: []const u8, exprText: []co
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub const TableDeleteArgs = struct { table: []const u8, exprText: []const u8 };
|
||||
|
||||
/// `table` and `exprText` are borrowed slices into `payload`, the same
|
||||
/// convention `decodeTableExplain`/`decodeTableUpdate` use.
|
||||
pub fn decodeTableDelete(payload: []const u8) !TableDeleteArgs {
|
||||
var c = Cursor{ .data = payload };
|
||||
const table = try c.takeLenPrefixed();
|
||||
const exprText = c.data[c.pos..];
|
||||
return .{ .table = table, .exprText = exprText };
|
||||
}
|
||||
|
||||
// --- table export / table import ---
|
||||
|
||||
/// Which interchange format a `table_export`/`table_import` request uses -
|
||||
/// the wire counterpart of the CLI's `csv`/`json` string argument (see
|
||||
/// `main.zig`'s local `table export`/`table import`), carried as one byte
|
||||
/// instead of a length-prefixed string since there are only ever two.
|
||||
pub const DumpFormat = enum(u8) {
|
||||
csv = 0,
|
||||
json = 1,
|
||||
};
|
||||
|
||||
/// Wire request for a remote `table export`: a table name and which format
|
||||
/// (`dump.zig`'s `exportCsvWriter`/`exportJsonWriter`) to render it in. No
|
||||
/// predicate/paging - export always dumps the whole table, matching the
|
||||
/// local CLI's `table export <table> csv|json <path>`.
|
||||
pub fn encodeTableExport(allocator: Allocator, table: []const u8, format: DumpFormat) ![]u8 {
|
||||
var buf = std.ArrayList(u8).init(allocator);
|
||||
errdefer buf.deinit();
|
||||
const w = encode.ByteWriter.init(&buf);
|
||||
try putLenPrefixed(w, table);
|
||||
try w.byte(@intFromEnum(format));
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub const TableExportArgs = struct { table: []const u8, format: DumpFormat };
|
||||
|
||||
pub fn decodeTableExport(payload: []const u8) !TableExportArgs {
|
||||
var c = Cursor{ .data = payload };
|
||||
const table = try c.takeLenPrefixed();
|
||||
const formatByte = try c.takeByte();
|
||||
const format = std.meta.intToEnum(DumpFormat, formatByte) catch return error.Malformed;
|
||||
return .{ .table = table, .format = format };
|
||||
}
|
||||
|
||||
/// Wire response for `table_export`: the row count `dump.zig`'s exporter
|
||||
/// reported (so the CLI can print the same count the local `table export`
|
||||
/// prints) followed by the rendered content bytes verbatim - a "count then
|
||||
/// rest of the payload" shape, the same idea `exprText` fields elsewhere in
|
||||
/// this file use for their own trailing variable-length piece.
|
||||
pub fn encodeExportResult(allocator: Allocator, rowCount: u64, content: []const u8) ![]u8 {
|
||||
var buf = std.ArrayList(u8).init(allocator);
|
||||
errdefer buf.deinit();
|
||||
const w = encode.ByteWriter.init(&buf);
|
||||
try w.putU64(rowCount);
|
||||
try w.slice(content);
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub const ExportResult = struct { rowCount: u64, content: []const u8 };
|
||||
|
||||
/// `content` is a borrowed slice into `payload`, the same convention
|
||||
/// `decodeTableExplain`'s `exprText` uses - the caller decides whether to
|
||||
/// copy it (`client.zig`'s `tableExport` dupes it into an allocation the
|
||||
/// caller owns once the response frame itself is about to be freed).
|
||||
pub fn decodeExportResult(payload: []const u8) !ExportResult {
|
||||
var c = Cursor{ .data = payload };
|
||||
const rowCount = try c.takeU64();
|
||||
const content = payload[c.pos..];
|
||||
return .{ .rowCount = rowCount, .content = content };
|
||||
}
|
||||
|
||||
/// Wire request for a remote `table import`: a table name, which format the
|
||||
/// following `content` bytes are encoded in, and the content itself.
|
||||
/// `content` comes last (decoded as "everything left in the payload", the
|
||||
/// same convention every `exprText` field in this file relies on) since it
|
||||
/// is arbitrary-length and, unlike `table`, needs no length prefix of its
|
||||
/// own.
|
||||
pub fn encodeTableImport(allocator: Allocator, table: []const u8, format: DumpFormat, content: []const u8) ![]u8 {
|
||||
var buf = std.ArrayList(u8).init(allocator);
|
||||
errdefer buf.deinit();
|
||||
const w = encode.ByteWriter.init(&buf);
|
||||
try putLenPrefixed(w, table);
|
||||
try w.byte(@intFromEnum(format));
|
||||
try w.slice(content);
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub const TableImportArgs = struct { table: []const u8, format: DumpFormat, content: []const u8 };
|
||||
|
||||
/// `table` and `content` are borrowed slices into `payload`, the same
|
||||
/// convention every other decode function in this file uses.
|
||||
pub fn decodeTableImport(payload: []const u8) !TableImportArgs {
|
||||
var c = Cursor{ .data = payload };
|
||||
const table = try c.takeLenPrefixed();
|
||||
const formatByte = try c.takeByte();
|
||||
const format = std.meta.intToEnum(DumpFormat, formatByte) catch return error.Malformed;
|
||||
const content = payload[c.pos..];
|
||||
return .{ .table = table, .format = format, .content = content };
|
||||
}
|
||||
|
||||
// --- stats ---
|
||||
|
||||
pub fn encodeStats(allocator: Allocator, stats: dbmod.Stats) ![]u8 {
|
||||
var buf = std.ArrayList(u8).init(allocator);
|
||||
errdefer buf.deinit();
|
||||
const w = encode.ByteWriter.init(&buf);
|
||||
try w.putU64(@intCast(stats.memtableEntries));
|
||||
try w.putU64(@intCast(stats.memtableBytes));
|
||||
try w.putU64(@intCast(stats.sstableCount));
|
||||
try w.putU64(stats.liveEntries);
|
||||
try w.putU64(stats.physicalBytes);
|
||||
try w.putU64(stats.cacheHits);
|
||||
try w.putU64(stats.cacheMisses);
|
||||
try w.putU64(stats.nextSeq);
|
||||
for (stats.levels) |level| {
|
||||
try w.putU64(@intCast(level.tables));
|
||||
try w.putU64(level.entries);
|
||||
try w.putU64(level.physicalBytes);
|
||||
}
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn decodeStats(payload: []const u8) !dbmod.Stats {
|
||||
var c = Cursor{ .data = payload };
|
||||
var stats = dbmod.Stats{};
|
||||
stats.memtableEntries = @intCast(try c.takeU64());
|
||||
stats.memtableBytes = @intCast(try c.takeU64());
|
||||
stats.sstableCount = @intCast(try c.takeU64());
|
||||
stats.liveEntries = try c.takeU64();
|
||||
stats.physicalBytes = try c.takeU64();
|
||||
stats.cacheHits = try c.takeU64();
|
||||
stats.cacheMisses = try c.takeU64();
|
||||
stats.nextSeq = try c.takeU64();
|
||||
var i: usize = 0;
|
||||
while (i < stats.levels.len) : (i += 1) {
|
||||
stats.levels[i] = .{
|
||||
.tables = @intCast(try c.takeU64()),
|
||||
.entries = try c.takeU64(),
|
||||
.physicalBytes = try c.takeU64(),
|
||||
};
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
|
||||
test "frame round trip through an in-memory buffer" {
|
||||
const allocator = std.testing.allocator;
|
||||
var buf = std.ArrayList(u8).init(allocator);
|
||||
defer buf.deinit();
|
||||
|
||||
try writeFrame(buf.writer(), @intFromEnum(Op.get), "hello");
|
||||
var stream = std.io.fixedBufferStream(buf.items);
|
||||
var frame = try readFrame(allocator, stream.reader());
|
||||
defer frame.deinit();
|
||||
|
||||
try std.testing.expectEqual(@intFromEnum(Op.get), frame.tag);
|
||||
try std.testing.expectEqualStrings("hello", frame.payload);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user