Steve Kinney

Validating the Data Layer

We’re still putting a lot of trust in our database layer as well. We should make sure that it’s also giving us back what we think it is.

There are a number of ways to go about this, but we might start with a simple abstraction.

class TaskClient {
  private database: Database;

  constructor(database: Database) {
    this.database = database;
  }

  async getTasks({ completed }: { completed: boolean }) {
    const query = completed
      ? await this.database.prepare('SELECT * FROM tasks WHERE completed = 1')
      : await this.database.prepare('SELECT * FROM tasks WHERE completed = 0');

    return TasksSchema.parse(await query.all());
  }

  async getTask(id: number) {
    const query = await this.database.prepare('SELECT * FROM tasks WHERE id = ?');
    return TaskSchema.or(z.undefined()).parse(await query.get([id]));
  }

  async createTask({ task }: { task: NewTask }) {
    const query = await this.database.prepare(
      'INSERT INTO tasks (title, description) VALUES (?, ?)',
    );
    await query.run([task.title, task.description]);
  }

  async updateTask(id: number, task: NewTask) {
    const previous = TaskSchema.parse(await this.getTask(id));
    const updated = { ...previous, ...task };

    const query = await this.database.prepare(
      `UPDATE tasks SET title = ?, description = ?, completed = ? WHERE id = ?`,
    );

    await query.run([updated.title, updated.description, updated.completed, id]);
  }

  async deleteTask(id: number) {
    const query = await this.database.prepare('DELETE FROM tasks WHERE id = ?');
    await query.run([id]);
  }
}

Adding Our Task Model to Our API Layer

Last modified on .