Query and manage your database with CanxJS's elegant ORM. Zero-config setup with MySQL and PostgreSQL support.
MySQL primary, PostgreSQL secondary support
Fluent API for building complex queries
Type-safe models with static methods
Built-in connection pooling for performance
1import { initDatabase, closeDatabase } from "canxjs";23// Initialize database connection4await initDatabase({5driver: "mysql", // or "postgresql"6host: "localhost",7port: 3306,8database: "myapp",9username: "root",10password: "password",11pool: { min: 2, max: 10 },12logging: true // Log SQL queries13});1415// Close connection on shutdown16process.on("SIGTERM", async () => {17await closeDatabase();18});
1import { Model } from "canxjs";23// Define a User model4export class User extends Model {5protected static tableName = "users";6protected static primaryKey = "id";7protected static timestamps = true; // auto: created_at, updated_at89// Type definition for the model10id!: number;11name!: string;12email!: string;13role!: string;14created_at!: Date;15updated_at!: Date;16updated_at!: Date;1718// Relations19posts() {20return this.hasMany(Post, "user_id");21}2223profile() {24return this.hasOne(Profile, "user_id");25}26}2728export class Post extends Model {29// ...30user() {31return this.belongsTo(User, "user_id");32}3334tags() {35return this.belongsToMany(Tag, "post_tags", "post_id", "tag_id");36}37}
To prevent unauthorized modifications, define $fillable (whitelist) or $guarded (blacklist) properties.
1export class User extends Model {2// Allow only these fields to be mass-assigned3protected static fillable = ["name", "email", "password"];45// OR block these fields (everything else is allowed)6protected static guarded = ["id", "is_admin", "balance"];7}
1// Find by primary key2const user = await User.find(1);34// Get all records5const users = await User.all();67// Create a new record8const newUser = await User.create({9name: "John Doe",10email: "john@example.com",11role: "user"12});1314// Update by ID15await User.updateById(1, { name: "Jane Doe" });1617// Delete by ID18await User.deleteById(1);
Define relationships as methods on your model class using hasOne, hasMany, belongsTo, and belongsToMany.
1import { Model } from "canxjs";23// Define a User model4export class User extends Model {5protected static tableName = "users";6protected static primaryKey = "id";7protected static timestamps = true; // auto: created_at, updated_at89// Type definition for the model10id!: number;11name!: string;12email!: string;13role!: string;14created_at!: Date;15updated_at!: Date;16updated_at!: Date;1718// Relations19posts() {20return this.hasMany(Post, "user_id");21}2223profile() {24return this.hasOne(Profile, "user_id");25}26}2728export class Post extends Model {29// ...30user() {31return this.belongsTo(User, "user_id");32}3334tags() {35return this.belongsToMany(Tag, "post_tags", "post_id", "tag_id");36}37}
1// Using the query builder for complex queries2const activeAdmins = await User.query()3.select("id", "name", "email")4.where("role", "=", "admin")5.where("status", "=", "active")6.orderBy("created_at", "desc")7.limit(10)8.get();910// With pagination11const page = 1;12const perPage = 20;13const users = await User.query()14.orderBy("id", "asc")15.limit(perPage)16.offset((page - 1) * perPage)17.get();1819// First record matching condition20const admin = await User.query()21.where("role", "=", "admin")22.first();
Paginate results automatically with the paginate() method.
1// Get paginated results (page 1, 15 items per page)2const result = await User.query()3.where("status", "=", "active")4.paginate(1, 15);56console.log(result);7/*8{9data: [...],10total: 45,11perPage: 15,12currentPage: 1,13lastPage: 314}15*/
1// Basic where2const users = await User.query()3.where("status", "=", "active")4.get();56// Multiple conditions (AND)7const results = await User.query()8.where("role", "=", "admin")9.where("status", "=", "active")10.get();1112// OR condition13const results = await User.query()14.where("role", "=", "admin")15.orWhere("role", "=", "moderator")16.get();1718// WHERE IN19const users = await User.query()20.whereIn("id", [1, 2, 3, 4, 5])21.get();2223// NULL checks24const unverified = await User.query()25.whereNull("email_verified_at")26.get();2728const verified = await User.query()29.whereNotNull("email_verified_at")30.get();
1// Inner join2const postsWithUsers = await Post.query()3.select("posts.*", "users.name as author")4.join("users", "posts.user_id", "=", "users.id")5.get();67// Left join8const results = await User.query()9.select("users.*")10.leftJoin("posts", "users.id", "=", "posts.user_id")11.get();
1// Count records2const totalUsers = await User.query().count();34// Sum5const totalSales = await Order.query()6.where("status", "=", "completed")7.sum("amount");89// Average10const avgRating = await Review.query().avg("rating");1112// Group by with aggregates13const salesByCategory = await Product.query()14.select("category")15.groupBy("category")16.get();
1// Execute raw SQL2const results = await User.query().raw(3"SELECT * FROM users WHERE created_at > ?",4["2024-01-01"]5);
CanxJS provides powerful eager loading capabilities to solve the N+1 query problem. You can load relationships at query time using with() or on existing models using load().
1// Eager load 'posts' relationship2const users = await User.query()3.with("posts")4.get();56// Eager load multiple relationships7const posts = await Post.query()8.with("author", "comments")9.get();1011// Lazy Eager Loading (on existing instance)12const user = await User.find(1);13await user.load("posts");