npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

jcc-eloquent

v1.0.0

Published

express Jcc eloquent ORM

Downloads

346

Readme

JCC Eloquent is a Node.js ORM (Object-Relational Mapping) framework inspired by Laravel's Eloquent. It facilitates interaction with databases through models, migrations, and a powerful query builder.

Features

  • Fluent API for building SQL queries
  • Support for SELECT, INSERT, UPDATE, and DELETE operations
  • Query methods including where, orWhere, orderBy, groupBy, having, join, innerJoin, leftJoin, rightJoin
  • Pagination with limit and offset
  • Support for relations and eager loading
  • Method chaining
  • Model class with Eloquent-like methods

Installation

npm install jcc-eloquent

Usage

Importing the ORM
import { Model } from "jcc-eloquent";

export class User extends Model {
  // Attributes hidden from JSON serialization
  protected static hidden: string[] = ["password"];

  // Attributes allowed for mass assignment
  protected static fillable: string[] = ["name"];

  // Attributes excluded from mass assignment
  protected static guarded: string[] = ["role_id"];

  // Enables soft delete functionality
  protected static softDelete: boolean = true;

  // Cast attributes with custom transformations
  protected static casts = {
    created_at: "date",
    getName: this.getName,
    setName: this.setName,
  };

  // Attribute getter - retrieves name in lowercase
  public static getName(value: any, attribute: any) {
    return `${value}`.toLowerCase();
  }

  // Attribute setter - sets name in uppercase
  public static setName(value: any, attribute: any) {
    return `${value}`.toUpperCase();
  }
}
  • Purpose: Represents a user in the application.
  • Properties:
    • hidden: An array of attribute names (like password) that should be excluded from the model's JSON representation.
    • softDelete: A boolean flag that enables soft deletes for the model, allowing records to be "deleted" without being permanently removed from the database.
    • casts: An object that specifies how certain attributes should be cast to specific types when accessed.

Post Model

import { Model } from "jcc-eloquent";

export class Post extends Model {
  // Attributes casting definitions
  protected static casts = {
    created_at: "now", // Example of default casting
  };

  // Relationship to the User model
  author() {
    return this.belongsTo("User", "user_id"); // Defines a belongs-to relationship
  }

  // Relationship to comments (polymorphic)
  comments() {
    return this.morphyMany("comments"); // Defines a polymorphic relationship
  }

  // Event hook for the creating event
  static booted(): void {
    this.creating((data) => {
      // Custom logic before creating a post (e.g., setting defaults)
    });

    this.created(() => {
      // Custom logic after creating a post (e.g., setting defaults)
    });

    this.updating(() => {
      // Custom logic before updating a post (e.g., setting defaults)
    });

    this.updated(() => {
      // Custom logic after updating a post (e.g., setting defaults)
    });

    this.deleting(() => {
      // Custom logic before deleting a post (e.g., setting defaults)
    });
  }
}

Model.all() Retrieves all records from the database table associated with the current model.

const users = await User.all();
console.log(users);

Model.find(id) Retrieves a single record from the database table associated with the current model by its ID.

const user = await User.find(1);
console.log(user);

Model.create(data) Creates one or more records in the database table associated with the current model.

const user = await User.create({
  name: "John Doe",
  email: "[email protected]",
  age: 30,
});
console.log(user);

const users = await User.create([
  { name: "Jane Doe", email: "[email protected]", age: 28 },
  { name: "John Smith", email: "[email protected]", age: 35 },
]);
console.log(users);

save() Saves the current instance to the database. If the instance has an id, it performs an update; otherwise, it performs an insert.

const user = new User();
user.name = "Abdou";
await user.save();

Relationship Definitions

  • hasOne(modelName, foreignKey = null, localKey = "id") Defines a one-to-one relationship between the current model and another model.

  • hasMany(model, foreignKey = null, localKey = "id") Defines a one-to-many relationship between the current model and another model.

  • belongsTo(modelName, foreignKey = null, localKey = "id") Defines a belongs-to relationship between the current model and another model.

Using Relationships

import { QueryBuilder } from "jcc-eloquent/QueryBuilder";

const user = await User.with("posts").get();
const post = await Post.with({ author(query:QueryBuilder) => query.where('status', 'active') } , 'comments').get();

Query Builder Methods

The following methods are available in the query builder:

  • select(...columns)
  • distinct()
  • from(tableName)
  • where(column, operator, value)
  • whereLike(column, searchValue)
  • orWhere(column, operator, value)
  • orderBy(column, direction)
  • limit(value)
  • take(value)
  • offset(count)
  • groupBy(...columns)
  • having(column, operator, value)
  • join(table, firstColumn, operator, secondColumn)
  • innerJoin(table, firstColumn, operator, secondColumn)
  • leftJoin(table, firstColumn, operator, secondColumn)
  • rightJoin(table, firstColumn, operator, secondColumn)
  • insert(data)
  • get()
  • update(data)
  • delete(id)
  • latest(column)
  • oldest(column)
  • with(...relations)
  • each(callback)
  • map(callback)
  • value(field)
  • exists()
  • doesntExist()
  • count()
  • max(column)
  • min(column)
  • sum(column)
  • avg(column)
  • paginate(request, perPage)
  • resetQuery()
  • onlyTrashed()
  • withTrashed()
  • restore()

Query Instance Methods

Once you've retrieved a model instance from the database, you can interact with it using the following methods:

1. save()

Description: Saves the current instance to the database. If it's a new instance, it will perform an INSERT; if it's an existing instance, it will perform an UPDATE.

Returns: Promise<any>

Example:

const user = await User.find(1);
user.name = "Updated Name";
await user.save(); // Updates the existing record

2. saveQuietly()

Description: Similar to save(), but suppresses any events that would normally be triggered during the save operation.

Returns: Promise<any>

Example:

import { Model } from "jcc-eloquent";

class Post extends Model {
  protected static booted() {
    this.created(async (data) => {
      data.slug = "slug";
      await data.saveQuietly(); // Saves without triggering any events
    });
  }
}

3. load(...relations: Array<any>)

Description: Eager loads relationships on the model instance.

Returns: Promise<any>

Example:

const user = await User.find(1);
await user.load("posts", "comments"); // Loads posts and comments for the user

4. update()

Description: Updates the current instance in the database with the new attribute values.

Returns: Promise<any>

Example:

const user = await User.find(1);
user.email = "[email protected]";
await user.update(); // Updates the email field in the database

5. delete()

Description: Deletes the current instance from the database.

Returns: Promise<boolean>

Example:

const post = await Post.find(1);
await post.delete(); // Deletes the post from the database

Query Instance Methods

Query Instance Methods Overview

The following methods are part of the Query Instance used for interacting with the database:

//Query Instance Methods
  save() ;
  saveQuietly();
  load(...relations: Array<any>): ; // Eager loads relationships
  update(); // Updates the current instance in the database
  delete(); // Deletes the current instance from the database
  • Methods:
    • save(): Persists the current instance to the database.
    • saveQuietly(): Saves the instance without firing any events (e.g., hooks).
    • load(): Loads specified relationships for the instance, eager loading them for optimization.
    • update(): Updates the current instance with new data.
    • delete(): Deletes the instance from the database, returning a boolean indicating success.

DB

It provides a fluent interface for building and executing SQL queries.

  • Purpose: Represents a blog post in the application.
  • Properties:
    • casts: Specifies how attributes should be cast. Here, created_at is set to a default value.
  • Methods:
    • author(): Defines a relationship to the User model indicating that a post belongs to a user.
    • comments(): Defines a polymorphic relationship to comments.
    • booted(): A lifecycle hook that runs custom logic before creating a post.

Migrations

CreateUsersTable Migration

import { Schema } from "jcc-eloquent";

export class Migration {
  async up() {
    return Schema.create("users", (table) => {
      table.id(); // Adds an auto-incrementing ID column
      table.string("name"); // Adds a string column for the user's name
      table.string("email").unique(); // Adds a unique string column for the user's email
      table.string("password"); // Adds a string column for the user's password
      table.timestamps(); // Adds created_at and updated_at timestamp columns
      table.softDeletes(); // Adds a deleted_at column for soft deletes
    });
  }

  async down() {
    return Schema.dropTable("users"); // Drops the users table
  }
}
  • Purpose: Manages the creation and deletion of the users table in the database.
  • Methods:
    • up(): Defines the schema for creating the users table with various columns and constraints.
    • down(): Defines the logic to drop the users table if the migration is rolled back.

CreatePostsTable Migration

import { Schema } from "jcc-eloquent";

export class CreatePostsTable {
  async up() {
    return Schema.create("posts", (table) => {
      table.id(); // Adds an auto-incrementing ID column
      table.unsignedBigInteger("user_id"); // Adds a user_id column as a foreign key
      table.text("body"); // Adds a text column for the post content
      table.foreign("user_id").references("id").on("users"); // Sets a foreign key constraint
      table.timestamps(); // Adds created_at and updated_at timestamp columns
      table.softDeletes(); // Adds a deleted_at column for soft deletes
    });
  }

  async down() {
    return Schema.dropTable("posts"); // Drops the posts table
  }
}
  • Purpose: Manages the creation and deletion of the posts table in the database.
  • Methods:
    • up(): Defines the schema for creating the posts table, including foreign key constraints to the users table.
    • down(): Defines the logic to drop the posts table if the migration is rolled back.

AddSlugToPostsTable Migration

import { Schema } from "jcc-eloquent";

export class Migration {
  async up() {
    return Schema.table("posts", (table) => {
      table.string("slug"); // Adds a slug column to the posts table
    });
  }

  async down() {
    return Schema.table("posts", (table) => {
      table.dropColumns("slug"); // Drops the slug column if rolled back
    });
  }
}
  • Purpose: Modifies the posts table to add a new slug column.
  • Methods:
    • up(): Adds the slug column to the posts table.
    • down(): Defines the logic to remove the slug column if the migration is rolled back.

Blueprint Class Overview

The Blueprint class is used to define the structure of database tables within migrations. Below is a list of its methods:

export declare class Blueprint {
  id(): this; // Adds an ID column
  unsignedBigInteger(column: string): any; // Adds an unsigned BIGINT column
  default(value: string): this; // Sets a default value for the last column
  foreign(column: string): this; // Defines a foreign key constraint
  references(column: string): this; // Specifies the referenced column
  cascade(): this; // Specifies cascade behavior on delete
  on(table: string): this; // Specifies the referenced table for foreign key
  string(column: string, length?: number | string): this; // Adds a VARCHAR column
  integer(column: string): this; // Adds an INT column
  bigInteger(column: string): this; // Adds a BIGINT column
  tinyInteger(column: string, size?: Number | string): this; // Adds a TINYINT column
  char(column: string, length?: number | string): this; // Adds a CHAR column
  text(column: string): this; // Adds a TEXT column
  mediumText(column: string): this; // Adds a MEDIUMTEXT column
  longText(column: string): this; // Adds a LONGTEXT column
  tinyText(column: string, length?: string | number): this; // Adds a TINYTEXT column
  boolean(column: string): number; // Adds a BOOL column
  binary(column: string, size: string | number): this; // Adds a BINARY column
  nullable(): this; // Sets the last added column to allow NULL values
  unique(): this; // Sets the last added column to have a UNIQUE constraint
  dateTime(column: string): this; // Adds a DATETIME column
  date(column: string): this; // Adds a DATE column
  enum(column: string, types?: Array<string>): this; // Adds an ENUM column
  morphs(column: string): void; // Adds columns for a polymorphic relationship
  comment(text: string): this; // Adds a comment to the last column
  timestamps(): any; // Adds created_at and updated_at columns
  dropColumns(...columns: Array<string>): number; // Drops specified columns
  renameColumn(from: string, to: string): number; // Renames a column
  change(): any; // Modifies the last added column's definition
  after(column: string): this; // Specifies position to add the column after
  softDeletes(): number; // Adds a deleted_at column for soft deletes}
  • Methods:
    • Each method is used to define a specific type of column or constraint within the schema, enabling fluent method chaining for ease of use.