feat: extend index
This commit is contained in:
1 parent
910afabd97
commit
9f207fd036
1 file changed
+155
+155
@@ -1268,3 +1268,158 @@ test "rowKey and indexEntryKey stay within their own namespace" {
|
||||
try std.testing.expectEqual(@as(u8, 'I'), ik[0]);
|
||||
}
|
||||
|
||||
test "prefixUpperBound bounds a prefix scan" {
|
||||
const allocator = std.testing.allocator;
|
||||
const upper = (try prefixUpperBound(allocator, "abc")).?;
|
||||
defer allocator.free(upper);
|
||||
try std.testing.expect(std.mem.order(u8, "abc", upper) == .lt);
|
||||
try std.testing.expect(std.mem.order(u8, "abd", upper) != .lt);
|
||||
}
|
||||
|
||||
test "IndexSet add remove save load round trip" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const dbPath = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(dbPath);
|
||||
|
||||
var db = try Db.open(allocator, dbPath, .{});
|
||||
defer db.close();
|
||||
|
||||
var set = try IndexSet.load(allocator, &db, "users");
|
||||
defer set.deinit();
|
||||
try std.testing.expectEqual(@as(usize, 0), set.fields.items.len);
|
||||
|
||||
try set.add("email");
|
||||
try set.add("age");
|
||||
try set.add("email");
|
||||
try std.testing.expectEqual(@as(usize, 2), set.fields.items.len);
|
||||
try set.save(&db, "users");
|
||||
|
||||
var reloaded = try IndexSet.load(allocator, &db, "users");
|
||||
defer reloaded.deinit();
|
||||
try std.testing.expect(reloaded.has("email"));
|
||||
try std.testing.expect(reloaded.has("age"));
|
||||
try std.testing.expect(!reloaded.has("missing"));
|
||||
|
||||
try std.testing.expect(reloaded.remove("email"));
|
||||
try std.testing.expect(!reloaded.remove("email"));
|
||||
try reloaded.save(&db, "users");
|
||||
|
||||
var third = try IndexSet.load(allocator, &db, "users");
|
||||
defer third.deinit();
|
||||
try std.testing.expect(!third.has("email"));
|
||||
try std.testing.expect(third.has("age"));
|
||||
}
|
||||
|
||||
test "UniqueSet add remove save load round trip" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const dbPath = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(dbPath);
|
||||
|
||||
var db = try Db.open(allocator, dbPath, .{});
|
||||
defer db.close();
|
||||
|
||||
var set = try UniqueSet.load(allocator, &db, "users");
|
||||
defer set.deinit();
|
||||
try std.testing.expectEqual(@as(usize, 0), set.fields.items.len);
|
||||
|
||||
try set.add("email");
|
||||
try set.add("ssn");
|
||||
try set.add("email");
|
||||
try std.testing.expectEqual(@as(usize, 2), set.fields.items.len);
|
||||
try set.save(&db, "users");
|
||||
|
||||
var reloaded = try UniqueSet.load(allocator, &db, "users");
|
||||
defer reloaded.deinit();
|
||||
try std.testing.expect(reloaded.has("email"));
|
||||
try std.testing.expect(reloaded.has("ssn"));
|
||||
try std.testing.expect(!reloaded.has("missing"));
|
||||
|
||||
try std.testing.expect(reloaded.remove("email"));
|
||||
try std.testing.expect(!reloaded.remove("email"));
|
||||
try reloaded.save(&db, "users");
|
||||
|
||||
var third = try UniqueSet.load(allocator, &db, "users");
|
||||
defer third.deinit();
|
||||
try std.testing.expect(!third.has("email"));
|
||||
try std.testing.expect(third.has("ssn"));
|
||||
}
|
||||
|
||||
test "UniqueSet and IndexSet on the same table never collide, each keeps its own membership" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const dbPath = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(dbPath);
|
||||
|
||||
var db = try Db.open(allocator, dbPath, .{});
|
||||
defer db.close();
|
||||
|
||||
var indexes = try IndexSet.load(allocator, &db, "users");
|
||||
defer indexes.deinit();
|
||||
try indexes.add("email");
|
||||
try indexes.add("city");
|
||||
try indexes.save(&db, "users");
|
||||
|
||||
var unique = try UniqueSet.load(allocator, &db, "users");
|
||||
defer unique.deinit();
|
||||
try unique.add("email");
|
||||
try unique.save(&db, "users");
|
||||
|
||||
// "city" is indexed but not unique, "email" is both - the two sets
|
||||
// must agree on "email" and disagree on "city" after an independent
|
||||
// reload of each, proving neither save() overwrote the other's key.
|
||||
var reloadedIndexes = try IndexSet.load(allocator, &db, "users");
|
||||
defer reloadedIndexes.deinit();
|
||||
var reloadedUnique = try UniqueSet.load(allocator, &db, "users");
|
||||
defer reloadedUnique.deinit();
|
||||
|
||||
try std.testing.expect(reloadedIndexes.has("email"));
|
||||
try std.testing.expect(reloadedIndexes.has("city"));
|
||||
try std.testing.expect(reloadedUnique.has("email"));
|
||||
try std.testing.expect(!reloadedUnique.has("city"));
|
||||
}
|
||||
|
||||
test "ForeignKeySet add remove save load round trip" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const dbPath = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(dbPath);
|
||||
|
||||
var db = try Db.open(allocator, dbPath, .{});
|
||||
defer db.close();
|
||||
|
||||
var set = try ForeignKeySet.load(allocator, &db, "orders");
|
||||
defer set.deinit();
|
||||
try std.testing.expectEqual(@as(usize, 0), set.specs.items.len);
|
||||
|
||||
try set.add("customer_id", "customers", "__pk", .cascade);
|
||||
try set.add("customer_id", "customers", "some_other_field", .restrict);
|
||||
try std.testing.expectEqual(@as(usize, 1), set.specs.items.len);
|
||||
try set.save(&db, "orders");
|
||||
|
||||
var reloaded = try ForeignKeySet.load(allocator, &db, "orders");
|
||||
defer reloaded.deinit();
|
||||
try std.testing.expect(reloaded.has("customer_id"));
|
||||
try std.testing.expect(!reloaded.has("missing"));
|
||||
const spec = reloaded.find("customer_id").?;
|
||||
try std.testing.expectEqualStrings("customers", spec.refTable);
|
||||
try std.testing.expectEqualStrings("__pk", spec.refField);
|
||||
// First `add` wins (mirrors `has` guard above) - `onDelete` survives the
|
||||
// save/load round trip as the mode from that first call, not the
|
||||
// no-op second one.
|
||||
try std.testing.expectEqual(OnDelete.cascade, spec.onDelete);
|
||||
|
||||
try std.testing.expect(reloaded.remove("customer_id"));
|
||||
try std.testing.expect(!reloaded.remove("customer_id"));
|
||||
try reloaded.save(&db, "orders");
|
||||
|
||||
var third = try ForeignKeySet.load(allocator, &db, "orders");
|
||||
defer third.deinit();
|
||||
try std.testing.expect(!third.has("customer_id"));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user