diff --git a/src/repl.zig b/src/repl.zig index 9dabf58..89b1b5a 100644 --- a/src/repl.zig +++ b/src/repl.zig @@ -788,3 +788,152 @@ pub const Repl = struct { } } + fn cmdCollCounter(self: *Repl, op: []const u8, args: []const []const u8, writer: anytype) !void { + const Counter = collectionsmod.Counter; + if (std.mem.eql(u8, op, "get")) { + if (args.len < 1) return ReplError.WrongArgCount; + const v = try Counter.get(self.db, self.allocator, args[0]); + try writer.print("{d}\n", .{v}); + } else if (std.mem.eql(u8, op, "set")) { + if (args.len < 2) return ReplError.WrongArgCount; + const v = std.fmt.parseInt(i64, args[1], 10) catch return ReplError.InvalidArgument; + try Counter.set(self.db, self.allocator, args[0], v); + try writer.writeAll("OK\n"); + } else if (std.mem.eql(u8, op, "incrby")) { + if (args.len < 2) return ReplError.WrongArgCount; + const delta = std.fmt.parseInt(i64, args[1], 10) catch return ReplError.InvalidArgument; + const v = try Counter.incrBy(self.db, self.allocator, args[0], delta); + try writer.print("{d}\n", .{v}); + } else { + return ReplError.UnknownCollectionOp; + } + } + + fn cmdCollHash(self: *Repl, op: []const u8, args: []const []const u8, writer: anytype) !void { + const Hash = collectionsmod.Hash; + if (std.mem.eql(u8, op, "set")) { + if (args.len < 3) return ReplError.WrongArgCount; + const created = try Hash.set(self.db, self.allocator, args[0], args[1], args[2]); + try writer.print("{s}\n", .{if (created) "created" else "updated"}); + } else if (std.mem.eql(u8, op, "get")) { + if (args.len < 2) return ReplError.WrongArgCount; + if (try Hash.get(self.db, self.allocator, args[0], args[1])) |v| { + defer self.allocator.free(v); + try writer.print("{s}\n", .{v}); + } else { + try writer.writeAll("(nil)\n"); + } + } else if (std.mem.eql(u8, op, "del")) { + if (args.len < 2) return ReplError.WrongArgCount; + const existed = try Hash.del(self.db, self.allocator, args[0], args[1]); + try writer.print("{d}\n", .{@intFromBool(existed)}); + } else if (std.mem.eql(u8, op, "len")) { + if (args.len < 1) return ReplError.WrongArgCount; + const n = try Hash.len(self.db, self.allocator, args[0]); + try writer.print("{d}\n", .{n}); + } else if (std.mem.eql(u8, op, "getall")) { + if (args.len < 1) return ReplError.WrongArgCount; + const fields = try Hash.getAll(self.db, self.allocator, args[0]); + defer { + for (fields) |f| f.free(self.allocator); + self.allocator.free(fields); + } + for (fields) |f| try writer.print("{s}\t{s}\n", .{ f.field, f.value }); + } else { + return ReplError.UnknownCollectionOp; + } + } + + fn cmdCollSet(self: *Repl, op: []const u8, args: []const []const u8, writer: anytype) !void { + const Set = collectionsmod.Set; + if (std.mem.eql(u8, op, "add")) { + if (args.len < 2) return ReplError.WrongArgCount; + const added = try Set.add(self.db, self.allocator, args[0], args[1]); + try writer.print("{d}\n", .{@intFromBool(added)}); + } else if (std.mem.eql(u8, op, "rem")) { + if (args.len < 2) return ReplError.WrongArgCount; + const removed = try Set.remove(self.db, self.allocator, args[0], args[1]); + try writer.print("{d}\n", .{@intFromBool(removed)}); + } else if (std.mem.eql(u8, op, "ismember")) { + if (args.len < 2) return ReplError.WrongArgCount; + const is = try Set.isMember(self.db, self.allocator, args[0], args[1]); + try writer.print("{d}\n", .{@intFromBool(is)}); + } else if (std.mem.eql(u8, op, "card")) { + if (args.len < 1) return ReplError.WrongArgCount; + const n = try Set.card(self.db, self.allocator, args[0]); + try writer.print("{d}\n", .{n}); + } else if (std.mem.eql(u8, op, "members")) { + if (args.len < 1) return ReplError.WrongArgCount; + const ms = try Set.members(self.db, self.allocator, args[0]); + defer { + for (ms) |m| self.allocator.free(m); + self.allocator.free(ms); + } + for (ms) |m| try writer.print("{s}\n", .{m}); + } else if (std.mem.eql(u8, op, "inter") or std.mem.eql(u8, op, "union")) { + if (args.len < 1) return ReplError.WrongArgCount; + _ = try collttlmod.expireIfDueMany(self.db, self.allocator, .set, args[1..], std.time.nanoTimestamp()); + const ms = if (std.mem.eql(u8, op, "inter")) + try Set.intersect(self.db, self.allocator, args) + else + try Set.unionOf(self.db, self.allocator, args); + defer { + for (ms) |m| self.allocator.free(m); + self.allocator.free(ms); + } + for (ms) |m| try writer.print("{s}\n", .{m}); + } else if (std.mem.eql(u8, op, "diff")) { + if (args.len < 2) return ReplError.WrongArgCount; + _ = try collttlmod.expireIfDueMany(self.db, self.allocator, .set, args[1..], std.time.nanoTimestamp()); + const ms = try Set.difference(self.db, self.allocator, args[0], args[1..]); + defer { + for (ms) |m| self.allocator.free(m); + self.allocator.free(ms); + } + for (ms) |m| try writer.print("{s}\n", .{m}); + } else { + return ReplError.UnknownCollectionOp; + } + } + + fn cmdCollList(self: *Repl, op: []const u8, args: []const []const u8, writer: anytype) !void { + const List = collectionsmod.List; + if (std.mem.eql(u8, op, "lpush")) { + if (args.len < 2) return ReplError.WrongArgCount; + try List.pushLeft(self.db, self.allocator, args[0], args[1]); + try writer.writeAll("OK\n"); + } else if (std.mem.eql(u8, op, "rpush")) { + if (args.len < 2) return ReplError.WrongArgCount; + try List.pushRight(self.db, self.allocator, args[0], args[1]); + try writer.writeAll("OK\n"); + } else if (std.mem.eql(u8, op, "lpop") or std.mem.eql(u8, op, "rpop")) { + if (args.len < 1) return ReplError.WrongArgCount; + const popped = if (std.mem.eql(u8, op, "lpop")) + try List.popLeft(self.db, self.allocator, args[0]) + else + try List.popRight(self.db, self.allocator, args[0]); + if (popped) |v| { + defer self.allocator.free(v); + try writer.print("{s}\n", .{v}); + } else { + try writer.writeAll("(nil)\n"); + } + } else if (std.mem.eql(u8, op, "len")) { + if (args.len < 1) return ReplError.WrongArgCount; + const n = try List.len(self.db, self.allocator, args[0]); + try writer.print("{d}\n", .{n}); + } else if (std.mem.eql(u8, op, "range")) { + if (args.len < 3) return ReplError.WrongArgCount; + const start = std.fmt.parseInt(i64, args[1], 10) catch return ReplError.InvalidArgument; + const stop = std.fmt.parseInt(i64, args[2], 10) catch return ReplError.InvalidArgument; + const vals = try List.range(self.db, self.allocator, args[0], start, stop); + defer { + for (vals) |v| self.allocator.free(v); + self.allocator.free(vals); + } + for (vals) |v| try writer.print("{s}\n", .{v}); + } else { + return ReplError.UnknownCollectionOp; + } + } +