From c281644719b15c1dd603113da78b6aa264e91fa7 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Wed, 2 Sep 2026 15:39:42 +0200 Subject: [PATCH] feat: extend collections --- src/collections.zig | 157 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/src/collections.zig b/src/collections.zig index 6a1abb5..f3aa611 100644 --- a/src/collections.zig +++ b/src/collections.zig @@ -1105,3 +1105,160 @@ test "counter incrBy rejects a real external conflict" { try std.testing.expectError(error.Conflict, txn.commit()); } +test "hash set get del getAll" { + const allocator = std.testing.allocator; + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + var db = try openTemp(&tmp, allocator); + defer db.close(); + + try std.testing.expect(try Hash.set(&db, allocator, "user:1", "name", "ada")); + try std.testing.expect(!try Hash.set(&db, allocator, "user:1", "name", "ada lovelace")); + try std.testing.expect(try Hash.set(&db, allocator, "user:1", "age", "36")); + + const name = (try Hash.get(&db, allocator, "user:1", "name")).?; + defer allocator.free(name); + try std.testing.expectEqualStrings("ada lovelace", name); + + try std.testing.expectEqual(@as(usize, 2), try Hash.len(&db, allocator, "user:1")); + + const all = try Hash.getAll(&db, allocator, "user:1"); + defer { + for (all) |f| f.free(allocator); + allocator.free(all); + } + try std.testing.expectEqual(@as(usize, 2), all.len); + + try std.testing.expect(try Hash.del(&db, allocator, "user:1", "age")); + try std.testing.expect(!try Hash.del(&db, allocator, "user:1", "age")); + try std.testing.expectEqual(@as(usize, 1), try Hash.len(&db, allocator, "user:1")); + try std.testing.expect(try Hash.get(&db, allocator, "user:1", "age") == null); +} + +test "set add remove isMember card members" { + const allocator = std.testing.allocator; + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + var db = try openTemp(&tmp, allocator); + defer db.close(); + + try std.testing.expect(try Set.add(&db, allocator, "tags", "zig")); + try std.testing.expect(!try Set.add(&db, allocator, "tags", "zig")); + try std.testing.expect(try Set.add(&db, allocator, "tags", "db")); + + try std.testing.expect(try Set.isMember(&db, allocator, "tags", "zig")); + try std.testing.expect(!try Set.isMember(&db, allocator, "tags", "rust")); + try std.testing.expectEqual(@as(usize, 2), try Set.card(&db, allocator, "tags")); + + const members = try Set.members(&db, allocator, "tags"); + defer { + for (members) |m| allocator.free(m); + allocator.free(members); + } + try std.testing.expectEqual(@as(usize, 2), members.len); + + try std.testing.expect(try Set.remove(&db, allocator, "tags", "zig")); + try std.testing.expect(!try Set.remove(&db, allocator, "tags", "zig")); + try std.testing.expectEqual(@as(usize, 1), try Set.card(&db, allocator, "tags")); +} + +test "set intersect union difference across multiple sets" { + const allocator = std.testing.allocator; + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + var db = try openTemp(&tmp, allocator); + defer db.close(); + + _ = try Set.add(&db, allocator, "a", "1"); + _ = try Set.add(&db, allocator, "a", "2"); + _ = try Set.add(&db, allocator, "a", "3"); + _ = try Set.add(&db, allocator, "b", "2"); + _ = try Set.add(&db, allocator, "b", "3"); + _ = try Set.add(&db, allocator, "b", "4"); + + const inter = try Set.intersect(&db, allocator, &.{ "a", "b" }); + defer { + for (inter) |m| allocator.free(m); + allocator.free(inter); + } + try std.testing.expectEqual(@as(usize, 2), inter.len); + + const uni = try Set.unionOf(&db, allocator, &.{ "a", "b" }); + defer { + for (uni) |m| allocator.free(m); + allocator.free(uni); + } + try std.testing.expectEqual(@as(usize, 4), uni.len); + + const diff = try Set.difference(&db, allocator, "a", &.{"b"}); + defer { + for (diff) |m| allocator.free(m); + allocator.free(diff); + } + try std.testing.expectEqual(@as(usize, 1), diff.len); + try std.testing.expectEqualStrings("1", diff[0]); +} + +test "list push pop both ends preserve order" { + const allocator = std.testing.allocator; + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + var db = try openTemp(&tmp, allocator); + defer db.close(); + + try List.pushRight(&db, allocator, "queue", "b"); + try List.pushRight(&db, allocator, "queue", "c"); + try List.pushLeft(&db, allocator, "queue", "a"); + try std.testing.expectEqual(@as(usize, 3), try List.len(&db, allocator, "queue")); + + const first = (try List.popLeft(&db, allocator, "queue")).?; + defer allocator.free(first); + try std.testing.expectEqualStrings("a", first); + + const last = (try List.popRight(&db, allocator, "queue")).?; + defer allocator.free(last); + try std.testing.expectEqualStrings("c", last); + + try std.testing.expectEqual(@as(usize, 1), try List.len(&db, allocator, "queue")); + try std.testing.expect(try List.popLeft(&db, allocator, "empty") == null); +} + +test "list range supports negative indices redis style" { + const allocator = std.testing.allocator; + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + var db = try openTemp(&tmp, allocator); + defer db.close(); + + try List.pushRight(&db, allocator, "l", "0"); + try List.pushRight(&db, allocator, "l", "1"); + try List.pushRight(&db, allocator, "l", "2"); + try List.pushRight(&db, allocator, "l", "3"); + try List.pushRight(&db, allocator, "l", "4"); + + const full = try List.range(&db, allocator, "l", 0, -1); + defer { + for (full) |v| allocator.free(v); + allocator.free(full); + } + try std.testing.expectEqual(@as(usize, 5), full.len); + try std.testing.expectEqualStrings("0", full[0]); + try std.testing.expectEqualStrings("4", full[4]); + + const lastTwo = try List.range(&db, allocator, "l", -2, -1); + defer { + for (lastTwo) |v| allocator.free(v); + allocator.free(lastTwo); + } + try std.testing.expectEqual(@as(usize, 2), lastTwo.len); + try std.testing.expectEqualStrings("3", lastTwo[0]); + try std.testing.expectEqualStrings("4", lastTwo[1]); + + const clamped = try List.range(&db, allocator, "l", -100, 100); + defer { + for (clamped) |v| allocator.free(v); + allocator.free(clamped); + } + try std.testing.expectEqual(@as(usize, 5), clamped.len); +} +