Skip to content

Code Overview

This document provides a brief overview of the code used to create a web application with a database using Accella.

Table Definition

We use Prisma’s schema for defining database tables and migrations. Based on the defined table information, migration files can be generated.

db/schema/main.prisma
model User {
id Int @id @default(autoincrement())
firstName String
lastName String
age Int?
}

O/R Mapping

Accella uses Accel Record, an ORM library designed with the Active Record pattern. It features a synchronous interface, so you don’t need to use await, and implicit lazy loading of associations.

import { User } from "src/models";
// Create a new user
const user: User = User.create({
firstName: "John",
lastName: "Doe",
});
// Update the user
user.update({
age: 26,
});
// Get all users
for (const user of User.all()) {
console.log(user.firstName);
}
// Find a user
const john: User | undefined = User.findBy({
firstName: "John",
lastName: "Doe",
});
// Delete the user
john?.delete();

Extending Model Classes

By extending the class corresponding to a model, you can define validations, callbacks, custom methods, and more.

src/models/user.ts
import { before } from "accel-record";
import { validates } from "accel-record/validations";
import { ApplicationRecord } from "./applicationRecord.js";
export class UserModel extends ApplicationRecord {
// Define validations for the model
static validations = validates(this, [
["firstName", { presence: true }],
["lastName", { presence: true }],
]);
@before("save")
myCallback() {
// this method is called before save
}
// Define a method to get the full name
get fullName(): string {
return `${this.firstName} ${this.lastName}`;
}
}

Preparing Pages

With file-based routing, no routing configuration is generally needed. Astro components allow you to write JavaScript logic and DOM structure in a single file, similar to React components or Vue SFCs, enabling type-safe template rendering.

src/pages/users/index.astro
---
import { paginate } from "accel-web";
import { User } from "src/models";
import Layout from "../layouts/Layout.astro";
const page = Number(Astro.locals.params.p) || 1;
const pager = paginate(User.order('id', 'desc'), {
page,
per: 10,
window: 2,
});
const { Nav, PageEntriesInfo } = pager;
---
<Layout>
<h2>User List</h2>
<table>
<thead>
<tr>
<th>ID</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{
pager.records.map((user) => (
<tr>
<td>{user.id}</td>
<td>{user.email}</td>
</tr>
))
}
</tbody>
</table>
<!-- Pagination -->
<div><Nav /></div>
<div><PageEntriesInfo /></div>
</Layout>

Testing

Vitest is set up to allow you to start testing immediately after starting the project. Additionally, factories for Accel Record are provided, making it easy to create test data.

tests/user.test.ts
import { User } from "src/models";
import { $User } from "./factories/user";
test("create a user", () => {
const user = $User.create({
firstName: "John",
lastName: "Doe",
});
expect(user.fullName).toBe("John Doe");
expect(User.count()).toBe(1);
});