Blog App Tutorial Part 4

Part 4 introduces categories and more advanced query patterns.

Create categories

ballerina
type CategoryRow record {
    int id;
    string name;
    string slug;
    string? description;
};

CategoryRow tech = check (check db.'from(Category).create({
    name: "Technology",
    slug: "technology",
    description: "Tech-related posts"
})).cloneWithType();

CategoryRow tutorial = check (check db.'from(Category).create({
    name: "Tutorial",
    slug: "tutorial",
    description: "Step-by-step guides"
})).cloneWithType();

Many-to-many linking via join table

ballerina
record {}? postRow = check db.'from(Post)
    .'where({status: {'equals: PUBLISHED}})
    .findFirst();

if postRow is record {} {
    PostRow post = check postRow.cloneWithType();

    _ = check db.rawExecute(
        "INSERT INTO post_categories (post_id, category_id) VALUES ($1, $2), ($3, $4)",
        [post.id, tech.id, post.id, tutorial.id]
    );
}

Complex AND/OR filters

ballerina
PostRow[] posts = check (check db.'from(Post)
    .'where({
        AND: [
            {
                OR: [
                    {status: {'equals: PUBLISHED}},
                    {status: {'equals: DRAFT}}
                ]
            },
            {title: {contains: "Ballerina"}}
        ]
    })
    .orderBy({createdAt: orm:DESC})
    .take(10)
    .findMany()).cloneWithType();

Projection with select

ballerina
record {}[] userEmails = check (check db.'from(User)
    .'select({id: true, email: true, name: true})
    .'where({status: {'equals: ACTIVE}})
    .findMany()).cloneWithType();

Aggregations (count posts per author)

ballerina
record {}? thambaruRow = check db.'from(User)
    .'where({email: {'equals: "hi@thambaru.com"}})
    .findUnique();

if thambaruRow is record {} {
    UserRow thambaru = check thambaruRow.cloneWithType();

    int postCount = check db.'from(Post)
        .'where({authorId: {'equals: thambaru.id}})
        .count();

    // use postCount
    _ = postCount;
}

Next step

Proceed to Part 5: Transactions & Raw SQL.