Skip to content

Relations

Relations shape reads only (they emit no DDL): declare them with the schema, and client.query(.t) reads a table and its relations in one statement.

pub const Schema = kzig.db.Schema(.{ .users = users, .posts = posts, .tags = tags, .post_tags = post_tags }, .{ .relations = .{
    .users = .{ .posts = .{ .many = .posts } }, // joined by the one back, or posts' key to users
    .posts = .{
        .author = .{ .one = .users, .fields = .{.authorId}, .references = .{.id} },
        .tags = .{ .many = .tags, .through = .post_tags },
    },
} });

const user = try db.query(.users).findFirst(arena, .{
    .where = kzig.db.eq(.id, id),
    .columns = .{ .passwordHash = false },
    .with = .{ .posts = .{ .orderBy = .{ .{ .createdAt, .desc } }, .limit = 10, .with = .{ .tags = true } } },
});
// user.?.posts[0].tags[0].name — a `one` reads as `?T`, a `many` as `[]const T`

many finds its join as kick/db does: the one back with the same relation_name, else the only untagged one back, else the target's single foreign key; two keys to the same table need a relation_name on each side. A wrong relation name or column is a compile error. The relations go into snapshot.json as kick/db's sidecar. task-api's workspaces module reads a workspace with its owner, members (with their users) and projects this way.