feat: build out index
This commit is contained in:
1 parent
5c72201c45
commit
1ca072480d
1 file changed
+160
+160
@@ -1577,3 +1577,163 @@ test "ForeignKeySet, UniqueSet, and IndexSet on the same table never collide" {
|
||||
try checks.add("qty_positive", "qty gt 0");
|
||||
try checks.save(&db, "orders");
|
||||
|
||||
var reloadedIndexes = try IndexSet.load(allocator, &db, "orders");
|
||||
defer reloadedIndexes.deinit();
|
||||
var reloadedUnique = try UniqueSet.load(allocator, &db, "orders");
|
||||
defer reloadedUnique.deinit();
|
||||
var reloadedFkeys = try ForeignKeySet.load(allocator, &db, "orders");
|
||||
defer reloadedFkeys.deinit();
|
||||
var reloadedChecks = try CheckConstraintSet.load(allocator, &db, "orders");
|
||||
defer reloadedChecks.deinit();
|
||||
|
||||
try std.testing.expect(reloadedIndexes.has("customer_id"));
|
||||
try std.testing.expect(reloadedUnique.has("order_number"));
|
||||
try std.testing.expect(!reloadedUnique.has("customer_id"));
|
||||
try std.testing.expect(reloadedFkeys.has("customer_id"));
|
||||
try std.testing.expect(!reloadedFkeys.has("order_number"));
|
||||
try std.testing.expect(reloadedChecks.has("qty_positive"));
|
||||
try std.testing.expect(!reloadedChecks.has("customer_id"));
|
||||
}
|
||||
|
||||
test "addEntry scanEq removeEntry 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();
|
||||
|
||||
try addEntry(&db, allocator, "users", "city", .{ .text = "warsaw" }, .{ .int = 1 });
|
||||
try addEntry(&db, allocator, "users", "city", .{ .text = "warsaw" }, .{ .int = 2 });
|
||||
try addEntry(&db, allocator, "users", "city", .{ .text = "krakow" }, .{ .int = 3 });
|
||||
|
||||
const warsawPks = try scanEq(&db, allocator, "users", "city", .{ .text = "warsaw" });
|
||||
defer {
|
||||
for (warsawPks) |v| v.free(allocator);
|
||||
allocator.free(warsawPks);
|
||||
}
|
||||
try std.testing.expectEqual(@as(usize, 2), warsawPks.len);
|
||||
|
||||
try removeEntry(&db, allocator, "users", "city", .{ .text = "warsaw" }, .{ .int = 1 });
|
||||
const afterRemove = try scanEq(&db, allocator, "users", "city", .{ .text = "warsaw" });
|
||||
defer {
|
||||
for (afterRemove) |v| v.free(allocator);
|
||||
allocator.free(afterRemove);
|
||||
}
|
||||
try std.testing.expectEqual(@as(usize, 1), afterRemove.len);
|
||||
try std.testing.expectEqual(@as(i64, 2), afterRemove[0].int);
|
||||
}
|
||||
|
||||
test "EqCursor streams the same pks as eager scanEq and can stop early" {
|
||||
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 i: i64 = 0;
|
||||
while (i < 20) : (i += 1) {
|
||||
try addEntry(&db, allocator, "users", "city", .{ .text = "warsaw" }, .{ .int = i });
|
||||
}
|
||||
|
||||
const eager = try scanEq(&db, allocator, "users", "city", .{ .text = "warsaw" });
|
||||
defer {
|
||||
for (eager) |v| v.free(allocator);
|
||||
allocator.free(eager);
|
||||
}
|
||||
try std.testing.expectEqual(@as(usize, 20), eager.len);
|
||||
|
||||
// Pull only the first three through the cursor, then drop it: this must
|
||||
// neither read nor decode the remaining seventeen entries, and the
|
||||
// testing allocator would flag a leak if the partially-consumed
|
||||
// RangeIterator's resources were not released on an early deinit.
|
||||
var cursor = try scanEqCursor(&db, allocator, "users", "city", .{ .text = "warsaw" });
|
||||
defer cursor.deinit();
|
||||
var pulled = std.ArrayList(Value).init(allocator);
|
||||
defer {
|
||||
for (pulled.items) |v| v.free(allocator);
|
||||
pulled.deinit();
|
||||
}
|
||||
var n: usize = 0;
|
||||
while (n < 3) : (n += 1) {
|
||||
const pk = (try cursor.next(allocator)).?;
|
||||
try pulled.append(pk);
|
||||
}
|
||||
try std.testing.expectEqual(@as(usize, 3), pulled.items.len);
|
||||
for (pulled.items, 0..) |v, idx2| {
|
||||
try std.testing.expectEqual(eager[idx2].int, v.int);
|
||||
}
|
||||
}
|
||||
|
||||
test "RangeCursor streams the same pks as eager scanRange and can stop early" {
|
||||
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 i: i64 = 0;
|
||||
while (i < 30) : (i += 1) {
|
||||
try addEntry(&db, allocator, "events", "score", .{ .int = i }, .{ .int = i });
|
||||
}
|
||||
|
||||
var cursor = try scanRangeCursor(&db, allocator, "events", "score", .{ .value = .{ .int = 5 }, .inclusive = true }, null);
|
||||
defer cursor.deinit();
|
||||
const first = (try cursor.next(allocator)).?;
|
||||
defer first.free(allocator);
|
||||
const second = (try cursor.next(allocator)).?;
|
||||
defer second.free(allocator);
|
||||
try std.testing.expectEqual(@as(i64, 5), first.int);
|
||||
try std.testing.expectEqual(@as(i64, 6), second.int);
|
||||
// cursor and its underlying iterator are dropped by `defer` here without
|
||||
// consuming the other 23 matches.
|
||||
}
|
||||
|
||||
test "scanRange respects bounds and inclusivity" {
|
||||
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 i: i64 = 0;
|
||||
while (i < 10) : (i += 1) {
|
||||
try addEntry(&db, allocator, "events", "score", .{ .int = i }, .{ .int = i });
|
||||
}
|
||||
|
||||
const all = try scanRange(&db, allocator, "events", "score", null, null);
|
||||
defer {
|
||||
for (all) |v| v.free(allocator);
|
||||
allocator.free(all);
|
||||
}
|
||||
try std.testing.expectEqual(@as(usize, 10), all.len);
|
||||
|
||||
const midInclusive = try scanRange(&db, allocator, "events", "score", .{ .value = .{ .int = 3 }, .inclusive = true }, .{ .value = .{ .int = 6 }, .inclusive = true });
|
||||
defer {
|
||||
for (midInclusive) |v| v.free(allocator);
|
||||
allocator.free(midInclusive);
|
||||
}
|
||||
try std.testing.expectEqual(@as(usize, 4), midInclusive.len);
|
||||
try std.testing.expectEqual(@as(i64, 3), midInclusive[0].int);
|
||||
try std.testing.expectEqual(@as(i64, 6), midInclusive[midInclusive.len - 1].int);
|
||||
|
||||
const midExclusive = try scanRange(&db, allocator, "events", "score", .{ .value = .{ .int = 3 }, .inclusive = false }, .{ .value = .{ .int = 6 }, .inclusive = false });
|
||||
defer {
|
||||
for (midExclusive) |v| v.free(allocator);
|
||||
allocator.free(midExclusive);
|
||||
}
|
||||
try std.testing.expectEqual(@as(usize, 2), midExclusive.len);
|
||||
try std.testing.expectEqual(@as(i64, 4), midExclusive[0].int);
|
||||
try std.testing.expectEqual(@as(i64, 5), midExclusive[1].int);
|
||||
|
||||
Reference in new issue
Block a user