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 🙏

© 2026 – Pkg Stats / Ryan Hefner

my-custom-backend-framework

v1.0.17

Published

This framework is a custom wrapper around Express.js, written in TypeScript.

Readme

The Open-Source Backend Framework

This framework is a custom wrapper around Express.js, written in TypeScript.

Below is an overview of the design patterns employed in the creation of this custom backend framework:

1. Use of Decorators

One of the primary reasons for choosing TypeScript over JavaScript was the ability to utilize decorators.

Why Are Decorators Used Here?

Decorators are employed to map custom models to their corresponding table types and columns. They facilitate the identification of models and columns by associating them with metadata.

Consider the implementation below:

src/orm/decorator.ts

Decorators in the Framework

This file defines custom decorators that simplify database schema mapping within TypeScript.

Key Decorators

  1. @Entity(tableName: string)

    Associates a class with a database table.
  2. @PrimaryKey()

    Marks a property as the primary key of the table.
    
    Validates the property type and updates metadata accordingly.
  3. @Column(columnName: string)

    Maps a property to a database column.
    
    Validates the property type and stores column metadata.

Purpose

These decorators leverage TypeScript's metadata reflection to:

  1. Define database schemas directly within the code.

  2. Simplify ORM-like functionality for database integration.

Additionally, more decorators are used in the expressWrapper to associate methods with specific request types. You can find them in the following file:

src/expressWrapper/decorator

@Post(path: string)

The @Post decorator is used to define HTTP POST routes for methods in a class. It ensures that the path starts with a / and attaches metadata to the method, specifying the HTTP method (POST) and the route path. This metadata is later used by the framework to register routes with the Express.js router, simplifying route management and keeping the code organized.

2. Migration Handler

The code in src/migrationHandler is designed to handle database migrations. Its primary responsibilities include generating and applying migrations.

The problem we are addressing here involves the following challenges:

  1. Generating a SQL file every time we make changes to our models.

  2. Tracking the SQL files, and knowing whether migrations have been generated or not.

  3. Generating new migrations when a table is added, a column is added or removed, or any other structural changes occur.

  4. Reversing migrations and tracking which migrations have been applied.

To tackle these challenges, we need to store the state of the migrations every time we generate one. To solve this, I have used the Memento Design Pattern.

Below is an overview of the classes and their responsibilities:

Key Classes

  1. MigrationGenerator

    The MigrationGenerator class is responsible for generating the SQL files that correspond to the changes in the model. This class ensures that every modification in the model results in an updated migration file.

  2. MigrationHistory

    Since we need to track the history of generated SQL files, the MigrationHistory class serves to store and maintain the history of applied migrations. It keeps a record of the migrations that have been generated, as well as their associated metadata (e.g., date, table modifications).

  3. MigrationSnapshot

    The MigrationSnapshot class is responsible for taking a snapshot of the current migration state and saving it to the migration history. Each time a new migration is generated, this class ensures that a snapshot of the current model structure is captured and stored.

How It Works

The MigrationGenerator uses the MigrationSnapshot to take a snapshot of the current model state after generating a new migration.

The MigrationHistory stores the state of the migrations, keeping track of which migrations have been generated and when.

The MigrationSnapshot interacts with the MigrationHistory to store the current migration state and any changes to the migration history.

This setup allows us to:

  1. Track the history of generated migrations.

  2. Apply and revert migrations as needed.

  3. Generate new migrations based on changes in the database schema.

Here, apply.script.ts and generate.script.ts script in migrationHandler is used to generate the sql file and apply the migrations. which is mapped in script of package.json to run from cli.

3. Custom ORM builder

We have used a Builder Pattern for generating SQL queries in an object-oriented way. This pattern allows constructing SQL queries step by step, improving readability, maintainability, and flexibility in how queries are built and executed. Here's an explanation of the system:

Overview

The MyORM class acts as the main interface for building SQL queries, and the QueryBuilder classes (InsertBuilder, UpdateBuilder, DeleteBuilder, SelectBuilder etc) are responsible for constructing the individual SQL queries. The WhereBuilder class handles filtering conditions in SELECT queries.

Key Components

MyORM:

This is the entry point to build SQL queries. It provides methods like insert(), update(), delete(), and select() to start building different types of SQL queries.

InsertBuilder, UpdateBuilder, DeleteBuilder, SelectBuilder:

These classes are responsible for generating SQL queries for inserting, updating, deleting, and selecting data, respectively. Each builder class provides specific methods for modifying the query and adding parameters.

WhereBuilder:

This class is used specifically for adding WHERE conditions to a SELECT query. It supports multiple conditions such as equality, inequality, greater than, less than, etc., and allows for building complex queries with AND or OR conditions.

How It Works

Insert Operation: The insert() method from MyORM returns an InsertBuilder, which allows adding values to the query. Once all values are added, the query can be executed.

Update Operation:

The update() method returns an UpdateBuilder, where fields to update are specified using set(), and conditions for updating are specified using where().

Delete Operation:

The delete() method returns a DeleteBuilder, allowing for the creation of DELETE queries.

Select Operation:

The select() method returns a SelectBuilder, and the from() method adds a FROM clause. The WhereBuilder is used to add conditions for filtering the data.

4. Singleton pattern used in provider (models provider, pool provider)

To ensure efficient resource management, the framework uses the Singleton Pattern for managing shared resources like the database connection pool. A single instance of the pool object is created during the initialization or registration of the custom ORM. This instance is then injected into other classes (e.g., ORM class, migration generator class) that require access to the same pool object.

Benefits:

  • Ensures only one instance of the pool object exists throughout the application.
  • Simplifies resource sharing across different components.
  • Improves performance by avoiding redundant object creation.

5. Chain of Responsibility Pattern for Route Mapping

The framework uses the Chain of Responsibility Pattern to manage the mapping of API routes and middleware. This pattern allows defining a chain of execution, specifying the order in which middleware and routes are processed. By implementing this pattern, the framework ensures a structured and flexible routing flow, enabling developers to define what comes next in the execution chain and streamline the routing logic.