Skip to main content
Module

x/vital/mod.ts>Model

A lightweight Postgres ORM for Deno
Latest
class Model
Abstract
import { Model } from "https://deno.land/x/vital@v1.1.1/mod.ts";

A base class to provide helper methods to querying the database.

You can define a class like so:

interface UserEntity {
  id: number;
  name: string;
  nicknames: string[];
  is_admin: boolean;
  config: { google_uri?: string };
  customClassProperty: string;
  company: Company | null;
}
class User extends Model {
  public tablename = "users";

  public id = 0;

  public name = "";

  public nicknames: string[] = []; // As postgres supports arrays: `nicknames text[] NOT NULL`

  public is_admin = false; // As postgres supports booleans: `is_admin boolean NOT NULL`

  public config: {
    google_uri?: string
  } = {}; // As postgres supports objects: `config json NOT NULL`

  public company_id = 0;

  public created_at = "";

  public updated_at = "";

  public customClassProperty = "hello world"; // Excluded when saving/updating

  public async getSomeData() {
    return await doSomething();
  }

  public async company(): Promise<Company | null> {
    return await Company.where([
      ['id', this.company_id]
    ]).first();
  }

  public async factoryDefaults(params: Partial<UserEntity> = {}) {
    return {
      company_id: params.company_id ?? (await Company.factory()).id,
      name: params.name ?? "Some name",
      // ...,
    }
  }
}
let user = await User.factory() // User { ... }
console.log(user.id); // 1
console.log(await user.company()); // Company { ... }
user = await User.where('id', user.id).first();
console.log(user.id); // 1
console.log(user.name) // "Some name"
const user2 = await User.factory({
  company_id: (await user.company()).id,
  name: "Hello",
});
console.log(user2.id); // 2
console.log(user2.name); // "Hello"
console.log((await user2.company()).id); // 1
user2.name = "World";
await user2.save();
console.log(user2.name); // "World";

Index Signatures

[k: string]: unknown

Properties

protected
abstract
tablename: string
abstract
id: (number | string)

Methods

private
getChildFieldNames(omit?: { id?: boolean; timestamps?: boolean; }): Promise<Array<string>>
protected
abstract
factoryDefaults<T>(params: [P in keyof T]?: T[P] | undefined): Promise<Record<string, unknown>> | Record<string, unknown>
delete(): Promise<void>

Delete the model from the database using the id. Will not modify the models properties

You can extend this if you need to something before or after deleting:

public async delete() {
  doSomethingBeforeDeleting();
  await super.delete();
  doSomethingElseNowRowHasBeenDeleted();
  console.log(await this.exists()); // false
}

If the table has foreign constraints and you wish to delete those along with this row, for example you have users, and comments, and comments as a foreign key user_id, then be sure to add user_id ... REFERENCES users ON DELETE CASCASE

exists(): Promise<boolean>

Check if this model exists in the database via the id

refresh(): Promise<void>

Refresh the model properties by fetching directly from the database. If the row in the database via the id does not exist, this method will simply return. An exists() call can aid in testing.

save(): Promise<void>

Save or update the model to the database.

If the model exists (eg the id property is set), this will update the model, using the values of the field names on the class, and exclude updating the id, created_at and updated_at fields

If the model doesn't exist (eg no id), this will insert a new row

Once all done, this will then update the class properties with the values inserted, and auto fields such as assigning the new created_at value (if your table uses auto timestamps for example)

You can also override this class if you needed to perform actions before or after saving:

public async save() {
  // do somthing before saving...
  // ...
  await super.save();
  // do something after
  // ...
}
withRelations<Entity>(...relations: string[]): Promise<Entity>

Specficially for when wanting to access relations.

Say you want to attach articles to the user. Problem with this is, articles is a method on the class, so it cant also be a property.

Static Methods

all<Model extends BaseModel>(this: new () => Model): Promise<Model[]>

Retrieve all records from the table

count<Model extends BaseModel>(this: new () => Model): Promise<number>
factory<Model extends BaseModel, Entity>(this: new () => Model, params?: Record<string, unknown>): Promise<Model>

Create a factory

Inserts a new record into the database and returns it as a model

first<Model extends BaseModel>(this: new () => Model): Promise<Model | null>

Selects the first row found. If constraints have been set, it will also use those.

latest<Model extends BaseModel>(this: new () => Model): Promise<Model | null>

Finds the latest row

limit<Model extends BaseModel>(this: new () => Model, amount: number): QueryBuilder<Model>
offset<Model extends BaseModel>(this: new () => Model, amount: number): QueryBuilder<Model>
orderBy<Model extends BaseModel>(this: new () => Model, data: [string, "asc" | "desc"]): QueryBuilder<Model>
select<Model extends BaseModel>(this: new () => Model, ...fields: string[]): QueryBuilder<Model>
where<Model extends BaseModel>(
this: new () => Model,
column: string,
value: unknown,
): QueryBuilder<Model>
where<Model extends BaseModel>(
this: new () => Model,
column: string,
operator: string,
value: unknown,
): QueryBuilder<Model>
whereIn<Model extends BaseModel>(
this: new () => Model,
field: string,
values: Array<unknown>,
): QueryBuilder<Model>