tiny.sql.branch
Defined in tiny.sql.
API (8)
Actions
Public operations.
Types and contracts
Public types and contracts.
Source
Source: lib/sql/src/branch.zig
zig
const std = @import("std");const version = @import("version.zig");const Allocator = std.mem.Allocator;const BranchError = error{ CommitNotFound, NonFastForward,};pub const Error = Allocator.Error || BranchError;pub const CommitEntry = struct { hash: version.Hash, parents: []const version.Hash = &.{},};pub const Checkout = struct { name: []const u8, head: version.Hash, working: version.WorkingSet, pub fn init(ref: version.Ref, root: version.Hash) Checkout { return .{ .name = ref.name, .head = ref.target, .working = version.WorkingSet.init(root), }; } pub fn withWorking(self: Checkout, root: version.Hash) Checkout { return .{ .name = self.name, .head = self.head, .working = self.working.withWorking(root), }; } pub fn stage(self: Checkout) Checkout { return .{ .name = self.name, .head = self.head, .working = self.working.stage(), }; } pub fn advance(self: Checkout, head: version.Hash, root: version.Hash) Checkout { return .{ .name = self.name, .head = head, .working = self.working.advance(root), }; }};const Ancestor = struct { hash: version.Hash, depth: usize,};const StackEntry = struct { hash: version.Hash, depth: usize,};pub fn commitEntry(commit: version.Commit) CommitEntry { return .{ .hash = commit.hash, .parents = commit.parents, };}pub fn checkout(ref: version.Ref, root: version.Hash) Checkout { return Checkout.init(ref, root);}pub fn canFastForward(allocator: Allocator, entries: []const CommitEntry, current: version.Hash, target: version.Hash) Error!bool { return try containsAncestor(allocator, entries, target, current);}pub fn fastForwardRef(allocator: Allocator, entries: []const CommitEntry, ref: *version.Ref, target: version.Hash) Error!void { if (!try canFastForward(allocator, entries, ref.target, target)) return error.NonFastForward; ref.target = target;}pub fn mergeBase(allocator: Allocator, entries: []const CommitEntry, left: version.Hash, right: version.Hash) Error!?version.Hash { var left_ancestors = try ancestors(allocator, entries, left); defer left_ancestors.deinit(allocator); var right_ancestors = try ancestors(allocator, entries, right); defer right_ancestors.deinit(allocator); var best: ?Ancestor = null; var best_score: usize = 0; for (left_ancestors.items) |left_ancestor| { for (right_ancestors.items) |right_ancestor| { if (!version.same(left_ancestor.hash, right_ancestor.hash)) continue; const score = left_ancestor.depth + right_ancestor.depth; if (best == null or score < best_score) { best = .{ .hash = left_ancestor.hash, .depth = score, }; best_score = score; } } } return if (best) |ancestor| ancestor.hash else null;}fn containsAncestor(allocator: Allocator, entries: []const CommitEntry, descendant: version.Hash, ancestor: version.Hash) Error!bool { var found = try ancestors(allocator, entries, descendant); defer found.deinit(allocator); for (found.items) |entry| { if (version.same(entry.hash, ancestor)) return true; } return false;}fn ancestors(allocator: Allocator, entries: []const CommitEntry, start: version.Hash) Error!std.ArrayList(Ancestor) { var found: std.ArrayList(Ancestor) = .empty; errdefer found.deinit(allocator); var stack: std.ArrayList(StackEntry) = .empty; defer stack.deinit(allocator); try stack.append(allocator, .{ .hash = start, .depth = 0 }); while (stack.pop()) |next| { if (contains(found.items, next.hash)) continue; try found.append(allocator, .{ .hash = next.hash, .depth = next.depth, }); const commit = find(entries, next.hash) orelse return error.CommitNotFound; for (commit.parents) |parent| { try stack.append(allocator, .{ .hash = parent, .depth = next.depth + 1, }); } } return found;}fn contains(entries: []const Ancestor, hash: version.Hash) bool { for (entries) |entry| { if (version.same(entry.hash, hash)) return true; } return false;}fn find(entries: []const CommitEntry, hash: version.Hash) ?CommitEntry { for (entries) |entry| { if (version.same(entry.hash, hash)) return entry; } return null;}test "branch fast-forward follows commit ancestry" { const root_commit = version.Commit.init(version.emptyHash("root"), &.{}); var left_parents = [_]version.Hash{root_commit.hash}; const left_commit = version.Commit.init(version.emptyHash("left"), left_parents[0..]); var right_parents = [_]version.Hash{left_commit.hash}; const right_commit = version.Commit.init(version.emptyHash("right"), right_parents[0..]); var side_parents = [_]version.Hash{left_commit.hash}; const side_commit = version.Commit.init(version.emptyHash("side"), side_parents[0..]); const entries = [_]CommitEntry{ commitEntry(root_commit), commitEntry(left_commit), commitEntry(right_commit), commitEntry(side_commit), }; try std.testing.expect(try canFastForward(std.testing.allocator, entries[0..], left_commit.hash, right_commit.hash)); try std.testing.expect(!try canFastForward(std.testing.allocator, entries[0..], side_commit.hash, right_commit.hash)); var ref = version.Ref{ .name = "main", .target = left_commit.hash, }; try fastForwardRef(std.testing.allocator, entries[0..], &ref, right_commit.hash); try std.testing.expect(version.same(ref.target, right_commit.hash)); try std.testing.expectError(error.NonFastForward, fastForwardRef(std.testing.allocator, entries[0..], &ref, side_commit.hash));}test "branch merge base chooses nearest common ancestor" { const root_commit = version.Commit.init(version.emptyHash("root"), &.{}); var first_parents = [_]version.Hash{root_commit.hash}; const first_commit = version.Commit.init(version.emptyHash("first"), first_parents[0..]); var left_parents = [_]version.Hash{first_commit.hash}; const left_commit = version.Commit.init(version.emptyHash("left"), left_parents[0..]); var right_parents = [_]version.Hash{first_commit.hash}; const right_commit = version.Commit.init(version.emptyHash("right"), right_parents[0..]); const entries = [_]CommitEntry{ commitEntry(root_commit), commitEntry(first_commit), commitEntry(left_commit), commitEntry(right_commit), }; const base = (try mergeBase(std.testing.allocator, entries[0..], left_commit.hash, right_commit.hash)).?; try std.testing.expect(version.same(first_commit.hash, base));}test "branch checkout keeps head and working state explicit" { const head = version.emptyHash("head-commit"); const root = version.emptyHash("head-root"); const working = version.emptyHash("working"); const next = version.emptyHash("next-commit"); const next_root = version.emptyHash("next-root"); const initial = checkout(.{ .name = "main", .target = head, }, root); try std.testing.expectEqualStrings("main", initial.name); try std.testing.expect(version.same(head, initial.head)); try std.testing.expect(version.same(root, initial.working.base)); try std.testing.expect(!initial.working.dirty()); try std.testing.expect(!initial.working.hasStaged()); const changed = initial.withWorking(working); try std.testing.expect(version.same(head, changed.head)); try std.testing.expect(changed.working.dirty()); try std.testing.expect(!changed.working.hasStaged()); const staged = changed.stage(); try std.testing.expect(staged.working.hasStaged()); try std.testing.expect(version.same(working, staged.working.staged)); const advanced = staged.advance(next, next_root); try std.testing.expect(version.same(next, advanced.head)); try std.testing.expect(version.same(next_root, advanced.working.base)); try std.testing.expect(!advanced.working.dirty()); try std.testing.expect(!advanced.working.hasStaged());}test "branch ancestry rejects missing commits" { const root_commit = version.Commit.init(version.emptyHash("root"), &.{}); const missing = version.emptyHash("missing"); const entries = [_]CommitEntry{commitEntry(root_commit)}; try std.testing.expectError(error.CommitNotFound, canFastForward(std.testing.allocator, entries[0..], root_commit.hash, missing));}Source: lib/sql/src/root.zig:23
zig
pub const branch = @import("branch.zig");Complete caller list for branch.canFastForward
7 direct callers.
tiny.sql.branch.fastForwardRef[function] atlib/sql/src/branch.zig:81lib.sql.src.branch.test_branch_ancestry_rejects_missing_commits[function] — test source atlib/sql/src/branch.zig:240in nearest public ownertiny.sql.branchlib.sql.src.branch.test_branch_fast-forward_follows_commit_ancestry[function] — test source atlib/sql/src/branch.zig:160in nearest public ownertiny.sql.branchlib.sql.src.history.store.test_history_recovers_branch_commits_and_merge_commits[function] — test source atlib/sql/src/history/store.zig:3542in nearest public ownerlib.sql.src.history.storelib.sql.src.history.store.test_history_recovers_commits_refs_and_conflicts[function] — test source atlib/sql/src/history/store.zig:2404in nearest public ownerlib.sql.src.history.storetiny.sql.repository.Repository[function] atlib/sql/src/repository/flow.zig:7lib.sql.src.sync.canFastForwardWithPack[function] — private source atlib/sql/src/sync.zig:1769in nearest public ownertiny.sql.sync
Complete caller list for branch.checkout
8 direct callers.
lib.sql.src.branch.test_branch_checkout_keeps_head_and_working_state_explicit[function] — test source atlib/sql/src/branch.zig:206in nearest public ownertiny.sql.branchtiny.sql.History.checkoutBranch[method] atlib/sql/src/history/store.zig:713lib.sql.src.plan.flushPreparedRelation[function] — private source atlib/sql/src/plan.zig:538in nearest public ownertiny.sql.planlib.sql.src.session.test.test_database_session_clears_analyzed_stats_after_relation_edits[function] — test source atlib/sql/src/session/test.zig:905in nearest public ownerlib.sql.src.session.testlib.sql.src.session.test.test_database_session_rejects_staged_relations_that_drift_from_working_values[function] — test source atlib/sql/src/session/test.zig:418in nearest public ownerlib.sql.src.session.testlib.sql.src.session.test.test_database_write_appends_staged_edits_to_staged_relations[function] — test source atlib/sql/src/session/test.zig:110in nearest public ownerlib.sql.src.session.testlib.sql.src.session.test.test_database_write_can_trust_staged_relation_indexes[function] — test source atlib/sql/src/session/test.zig:331in nearest public ownerlib.sql.src.session.testlib.sql.src.session.test.test_database_write_limits_bound_staged_edit_storage[function] — test source atlib/sql/src/session/test.zig:185in nearest public ownerlib.sql.src.session.test
Audit
| Definitions | 7 |
|---|---|
| Public names | 7 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |