feat: add handleTableUpdate and handleTableDelete to server
This commit is contained in:
1 parent
9b3ffe3d4b
commit
018ecace14
1 file changed
+152
+152
@@ -1699,3 +1699,155 @@ pub const Server = struct {
|
||||
};
|
||||
defer plan.deinit(self.allocator);
|
||||
|
||||
const out = protocol.encodePlan(self.allocator, plan) catch |err| {
|
||||
return writeErr(writer, .internal, @errorName(err));
|
||||
};
|
||||
defer self.allocator.free(out);
|
||||
try protocol.writeFrame(writer, @intFromEnum(protocol.Status.ok), out);
|
||||
}
|
||||
|
||||
/// Executes a `table_update` request: the network counterpart of the
|
||||
/// CLI's local `table update <table> --set ... [expr...]`, running
|
||||
/// `query.Table.updateWhere` against the server's `*Db`. The wire
|
||||
/// `sets` field list arrives pre-encoded with `Row.encode` (the same
|
||||
/// trick `decodeTxnOp`'s `fieldsBytes` uses), so it is decoded into a
|
||||
/// real `Row` here before `updateWhere` ever sees it. The response is a
|
||||
/// bare row count reusing `encodeTtlSweepCount`'s u64 wire shape - the
|
||||
/// same "no new response type, an existing shape already fits"
|
||||
/// precedent `coll_ttl_op` set for `ttl_op`'s result encoding.
|
||||
fn handleTableUpdate(self: *Server, payload: []const u8, writer: anytype) !void {
|
||||
const args = protocol.decodeTableUpdate(payload) catch {
|
||||
return writeErr(writer, .bad_request, "malformed table_update payload");
|
||||
};
|
||||
|
||||
var setsRow = rowmod.Row.decode(self.allocator, args.setsBytes) catch {
|
||||
return writeErr(writer, .bad_request, "malformed table_update set fields");
|
||||
};
|
||||
defer setsRow.deinit();
|
||||
|
||||
var table = querymod.Table.open(self.db, self.allocator, args.table) catch |err| {
|
||||
return writeErr(writer, .bad_request, @errorName(err));
|
||||
};
|
||||
defer table.deinit();
|
||||
|
||||
var parsed: ?exprmod.Parsed = null;
|
||||
defer if (parsed) |*p| p.deinit();
|
||||
if (args.exprText.len > 0) {
|
||||
parsed = exprmod.parse(self.allocator, args.exprText) catch |err| {
|
||||
return writeErr(writer, .bad_request, @errorName(err));
|
||||
};
|
||||
}
|
||||
const pred: ?querymod.Predicate = if (parsed) |p| p.predicate else null;
|
||||
|
||||
const updated = table.updateWhere(pred, setsRow.fields.items) catch |err| {
|
||||
return writeErr(writer, .internal, @errorName(err));
|
||||
};
|
||||
|
||||
const out = protocol.encodeTtlSweepCount(self.allocator, @intCast(updated)) catch |err| {
|
||||
return writeErr(writer, .internal, @errorName(err));
|
||||
};
|
||||
defer self.allocator.free(out);
|
||||
try protocol.writeFrame(writer, @intFromEnum(protocol.Status.ok), out);
|
||||
}
|
||||
|
||||
/// Executes a `table_delete` request: the network counterpart of the
|
||||
/// CLI's local `table delete <table> [expr...]`, running
|
||||
/// `query.Table.deleteWhere` against the server's `*Db`. Same wire shape
|
||||
/// as `table_explain` (table + exprText, no `SET` clause) and same
|
||||
/// response shape as `table_update` (a bare row count reusing
|
||||
/// `encodeTtlSweepCount`'s u64 wire shape).
|
||||
fn handleTableDelete(self: *Server, payload: []const u8, writer: anytype) !void {
|
||||
const args = protocol.decodeTableDelete(payload) catch {
|
||||
return writeErr(writer, .bad_request, "malformed table_delete payload");
|
||||
};
|
||||
|
||||
var table = querymod.Table.open(self.db, self.allocator, args.table) catch |err| {
|
||||
return writeErr(writer, .bad_request, @errorName(err));
|
||||
};
|
||||
defer table.deinit();
|
||||
|
||||
var parsed: ?exprmod.Parsed = null;
|
||||
defer if (parsed) |*p| p.deinit();
|
||||
if (args.exprText.len > 0) {
|
||||
parsed = exprmod.parse(self.allocator, args.exprText) catch |err| {
|
||||
return writeErr(writer, .bad_request, @errorName(err));
|
||||
};
|
||||
}
|
||||
const pred: ?querymod.Predicate = if (parsed) |p| p.predicate else null;
|
||||
|
||||
const deleted = table.deleteWhere(pred) catch |err| {
|
||||
return writeErr(writer, .internal, @errorName(err));
|
||||
};
|
||||
|
||||
const out = protocol.encodeTtlSweepCount(self.allocator, @intCast(deleted)) catch |err| {
|
||||
return writeErr(writer, .internal, @errorName(err));
|
||||
};
|
||||
defer self.allocator.free(out);
|
||||
try protocol.writeFrame(writer, @intFromEnum(protocol.Status.ok), out);
|
||||
}
|
||||
|
||||
/// Executes a `table_export` request: the network counterpart of the
|
||||
/// CLI's local `table export <table> csv|json <path>`, rendering the
|
||||
/// whole table through `dump.zig`'s `exportCsvWriter`/`exportJsonWriter`
|
||||
/// (the same functions the local path calls, just pointed at an
|
||||
/// in-memory `ArrayList` writer instead of a file, since there is no
|
||||
/// filesystem path to write to on the server side of a request) and
|
||||
/// sending the row count plus the rendered bytes back in one frame.
|
||||
fn handleTableExport(self: *Server, payload: []const u8, writer: anytype) !void {
|
||||
const args = protocol.decodeTableExport(payload) catch {
|
||||
return writeErr(writer, .bad_request, "malformed table_export payload");
|
||||
};
|
||||
|
||||
var table = querymod.Table.open(self.db, self.allocator, args.table) catch |err| {
|
||||
return writeErr(writer, .bad_request, @errorName(err));
|
||||
};
|
||||
defer table.deinit();
|
||||
|
||||
var buf = std.ArrayList(u8).init(self.allocator);
|
||||
defer buf.deinit();
|
||||
const rowCount = switch (args.format) {
|
||||
.csv => dumpmod.exportCsvWriter(self.allocator, &table, buf.writer()),
|
||||
.json => dumpmod.exportJsonWriter(self.allocator, &table, buf.writer()),
|
||||
} catch |err| {
|
||||
return writeErr(writer, .internal, @errorName(err));
|
||||
};
|
||||
|
||||
const out = protocol.encodeExportResult(self.allocator, @intCast(rowCount), buf.items) catch |err| {
|
||||
return writeErr(writer, .internal, @errorName(err));
|
||||
};
|
||||
defer self.allocator.free(out);
|
||||
try protocol.writeFrame(writer, @intFromEnum(protocol.Status.ok), out);
|
||||
}
|
||||
|
||||
/// Executes a `table_import` request: the network counterpart of the
|
||||
/// CLI's local `table import <table> csv|json <path>`, feeding the
|
||||
/// wire-carried `content` bytes straight into `dump.zig`'s
|
||||
/// `importCsvContent`/`importJsonContent` (the same functions the local
|
||||
/// path calls after reading a file into memory - the client already did
|
||||
/// that reading, so the server only ever sees bytes, never a path)
|
||||
/// against the server's `*Db`. The response is a bare row count, the
|
||||
/// same u64 wire shape `table_update`/`table_delete` already use.
|
||||
fn handleTableImport(self: *Server, payload: []const u8, writer: anytype) !void {
|
||||
const args = protocol.decodeTableImport(payload) catch {
|
||||
return writeErr(writer, .bad_request, "malformed table_import payload");
|
||||
};
|
||||
|
||||
var table = querymod.Table.open(self.db, self.allocator, args.table) catch |err| {
|
||||
return writeErr(writer, .bad_request, @errorName(err));
|
||||
};
|
||||
defer table.deinit();
|
||||
|
||||
const imported = switch (args.format) {
|
||||
.csv => dumpmod.importCsvContent(self.allocator, &table, args.content),
|
||||
.json => dumpmod.importJsonContent(self.allocator, &table, args.content),
|
||||
} catch |err| {
|
||||
return writeErr(writer, .internal, @errorName(err));
|
||||
};
|
||||
|
||||
const out = protocol.encodeTtlSweepCount(self.allocator, @intCast(imported)) catch |err| {
|
||||
return writeErr(writer, .internal, @errorName(err));
|
||||
};
|
||||
defer self.allocator.free(out);
|
||||
try protocol.writeFrame(writer, @intFromEnum(protocol.Status.ok), out);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user