All files / dal blog-projects.dal.ts

100% Statements 27/27
100% Branches 8/8
100% Functions 8/8
100% Lines 23/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113              32x     2x               1x       1x             2x         2x       2x       2x       1x                         5x   3x           3x 3x 6x 6x   3x                         4x   3x                           3x       3x 3x 3x   3x      
// Data Access Layer for Blog Projects (project links)
import { eq, inArray } from "drizzle-orm";
import type { DrizzleD1Database } from "drizzle-orm/d1";
import * as schema from "../db/schema";
import type { BlogProject, NewBlogProject } from "../db/schema";
 
export class BlogProjectsDal {
	constructor(private db: DrizzleD1Database<typeof schema>) {}
 
	async findByBlogId(blogId: string): Promise<BlogProject[]> {
		return this.db
			.select()
			.from(schema.blogProjects)
			.where(eq(schema.blogProjects.blogId, blogId))
			.orderBy(schema.blogProjects.displayOrder);
	}
 
	async create(data: NewBlogProject): Promise<BlogProject> {
		const result = await this.db
			.insert(schema.blogProjects)
			.values(data)
			.returning();
		return result[0];
	}
 
	async updateOrder(
		id: string,
		displayOrder: number,
	): Promise<BlogProject | undefined> {
		const result = await this.db
			.update(schema.blogProjects)
			.set({ displayOrder })
			.where(eq(schema.blogProjects.id, id))
			.returning();
		return result[0];
	}
 
	async delete(id: string): Promise<boolean> {
		const result = await this.db
			.delete(schema.blogProjects)
			.where(eq(schema.blogProjects.id, id))
			.returning();
		return result.length > 0;
	}
 
	async removeAllFromBlog(blogId: string): Promise<void> {
		await this.db
			.delete(schema.blogProjects)
			.where(eq(schema.blogProjects.blogId, blogId));
	}
 
	/**
	 * Bulk fetch blog projects for multiple blogs (N+1 optimization)
	 * @param blogIds Array of blog IDs
	 * @returns Map of blogId -> BlogProject[]
	 */
	async findByBlogIds(
		blogIds: string[],
	): Promise<Map<string, BlogProject[]>> {
		if (blogIds.length === 0) return new Map();
 
		const result = await this.db
			.select()
			.from(schema.blogProjects)
			.where(inArray(schema.blogProjects.blogId, blogIds))
			.orderBy(schema.blogProjects.displayOrder);
 
		const map = new Map<string, BlogProject[]>();
		for (const row of result) {
			if (!map.has(row.blogId)) map.set(row.blogId, []);
			map.get(row.blogId)?.push(row);
		}
		return map;
	}
 
	/**
	 * Bulk fetch projects (full project entities with display order) for multiple blogs (N+1 optimization)
	 * @param blogIds Array of blog IDs
	 * @returns Map of blogId -> Array of {project, displayOrder}
	 */
	async findFullProjectsByBlogIds(
		blogIds: string[],
	): Promise<
		Map<string, Array<{ project: schema.Project; displayOrder: number }>>
	> {
		if (blogIds.length === 0) return new Map();
 
		const result = await this.db
			.select({
				blogId: schema.blogProjects.blogId,
				project: schema.projects,
				displayOrder: schema.blogProjects.displayOrder,
			})
			.from(schema.blogProjects)
			.innerJoin(
				schema.projects,
				eq(schema.projects.id, schema.blogProjects.projectId),
			)
			.where(inArray(schema.blogProjects.blogId, blogIds))
			.orderBy(schema.blogProjects.displayOrder);
 
		const map = new Map<
			string,
			Array<{ project: schema.Project; displayOrder: number }>
		>();
		for (const { blogId, project, displayOrder } of result) {
			if (!map.has(blogId)) map.set(blogId, []);
			map.get(blogId)?.push({ project, displayOrder });
		}
		return map;
	}
}