Model Types
In this page, we introduce the model types in the ORM library Accel Record.
NewModel and PersistedModel
Accel Record provides two types, NewModel
and PersistedModel
, to distinguish between newly created and saved models.
Depending on the schema definition, some properties in NewModel
allow undefined
, while PersistedModel
does not.
This allows you to handle both pre-save and post-save models in a type-safe manner.
import { User, NewUser } from "./models/index.js";
/*Example of NewModel:NewUser represents a pre-save model and has the following type:
interface NewUser { id: number | undefined; firstName: string | undefined; lastName: string | undefined; age: number | undefined;}*/const newUser: NewUser = User.build({});
/*Example of PersistedModel:User represents a saved model and has the following type:
interface User { id: number; firstName: string; lastName: string; age: number | undefined;}*/const persistedUser: User = User.first()!;
BaseModel
The above NewModel
and PersistedModel
inherit from BaseModel
.
Methods defined in BaseModel
can be used by both NewModel
and PersistedModel
.
import { ApplicationRecord } from "./applicationRecord.js";
/*Example of BaseModel:UserModel corresponds to `NewUser` and `User` in `BaseModel`. */export class UserModel extends ApplicationRecord { // Methods defined here can be used by both `NewUser` and `User`. get fullName(): string | undefined { if (!this.firstName || !this.lastName) { // For `NewUser`, we need to consider the possibility of `firstName` and `lastName` being `undefined`. return undefined; } return `${this.firstName} ${this.lastName}`; }}
import { User, NewUser } from "./models/index.js";
const newUser: NewUser = User.build({});console.log(newUser.fullName); // => undefined
const user: User = User.first()!;console.log(user.fullName); // => "John Doe"
You can also define methods that are type-safe and can only be used by PersistedModel
by specifying the this
type for the method. (In this case, the get
keyword cannot be used due to TypeScript specifications)
import { ApplicationRecord } from "./applicationRecord.js";import { User } from "./index.js";
export class UserModel extends ApplicationRecord { // This method can only be used by `User` and is type-safe. Using it with `NewUser` will result in a type error. fullName(this: User): string { return `${this.firstName} ${this.lastName}`; }}
import { User, NewUser } from "./models/index.js";
const newUser: NewUser = User.build({});// @ts-expect-errornewUser.fullName();// => The 'this' context of type 'NewUser' is not assignable to method's 'this' of type 'User'.
const user: User = User.first()!;console.log(user.fullName()); // => "John Doe"
Converting from NewModel to PersistedModel
By using methods like save()
and isPersisted()
, you can convert a NewModel
type to a PersistedModel
type.
import { User, NewUser } from "./models/index.js";
// Prepare a user of NewModel typeconst user: NewUser = User.build({ firstName: "John", lastName: "Doe",});
if (user.save()) { // If save is successful, the NewModel is converted to PersistedModel. // In this block, the user can be treated as User type. console.log(user.id); // user.id is of type number} else { // If save fails, the NewModel remains the same type. // In this block, the user remains as NewUser type. console.log(user.id); // user.id is of type number | undefined}
const someFunc = (user: NewUser | User) => { if (user.isPersisted()) { // If isPersisted() is true, the NewModel is converted to PersistedModel. // In this block, the user can be treated as User type. console.log(user.id); // user.id is of type number } else { // If isPersisted() is false, the NewModel remains the same type. // In this block, the user remains as NewUser type. console.log(user.id); // user.id is of type number | undefined }};