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

@itrocks/storage

v0.0.25

Published

Transforms model objects to and from storage systems

Readme

npm version npm downloads GitHub issues discord

storage

Transforms model objects to and from storage systems.

Overview

@itrocks/storage is an abstraction layer module offering a unified API for managing data across various storage systems, such as databases, files, or APIs. It simplifies CRUD operations and object relationship handling, independent of the underlying data source.

Core components

  • DataSource: The core abstraction for connecting to and performing operations on a storage system. It provides generic CRUD methods and is designed to be extended for specific storage implementations (e.g., MySQL, PostgreSQL, files, or even APIs).

  • Entity: An Entity represents a model object linked to a persistent resource in the storage system, such as after reading or writing it using data source features. Each Entity is expected to have a unique Identifier (id).

  • SearchType: A flexible object query structure used to define search criteria for finding entities in the storage.

Installation

npm i @itrocks/storage

Basic usage

Setting up a data source

To set up a data source, use the createDataSource function, which initializes a DataSource based on a configuration object and registers it under a specific name.

import { createDataSource, ds } from '@itrocks/storage'

// Configure a main MySQL data source
createDataSource({
	engine:   '@itrocks/mysql',
	host:     'localhost',
	user:     'root',
	password: 'password',
	database: 'example_db'
})

// Access the default (main) data source
const dataSource = ds()

CRUD Operations

The following example demonstrates common data access patterns:

// Saving an Entity
await dataSource.save(new User({ name: 'John Doe' }))

// Reading an Entity by ID
const user = await dataSource.read(User, 1)

// Searching for Entities
const activeUsers = await dataSource.search(User, { active: true })

// Deleting an Entity
await dataSource.delete(user)

Creating a Custom Data Source

To create a custom data source implementation, extend the DataSource abstract class and implement its methods:

import { KeyOf, Type } from '@itrocks/class-type'
import { DataSource, Entity } from '@itrocks/storage'

export class MyCustomDataSource extends DataSource
{
	constructor(configuration: { someConfigOption: string }) {
		super()
		// Save custom configuration
	}
	async delete<T extends object>(object: Entity<T>, property: KeyOf<Entity<T>> = 'id'): Promise<T> {
		// Custom delete logic
	}
	async deleteId<T extends object>(type: Type<T>, id: Identifier, property?: KeyOf<Entity<T>>) {
		// Custom delete by id logic
	}
	async deleteRelatedId<T extends Entity>(object: T, property: KeyOf<T>, id: Identifier) {
		// Custom delete by related object property id
	}
	insertRelatedId<T extends Entity>(object: T, property: KeyOf<T>, id: Identifier) {
		// Custom insert by related object property id
	}
	async read<T extends object>(type: Type<T>, id: Identifier): Promise<Entity<T>> {
		// Custom read logic
	}
	async readCollection<T extends object, PT extends object>(object: Entity<T>, property: KeyOf<T>, type?: Type<PT>): Promise<Entity<PT>[]> {
		// Custom collection object read logic
	}
	async readCollectionIds<T extends object, PT extends object>(object: Entity<T>, property: KeyOf<T>, type?: Type<PT>): Promise<Identifier[]> {
		// Custom collection object id read logic
	}
  async readMultiple<T extends object>(type: Type<T>, ids: Identifier[]): Promise<Entity<T>[]> {
    // Custom read multiple objects 
  }
	async save<T extends object>(object: MayEntity<T>): Promise<Entity<T>> {
		// Custom save logic
	}
	async search<T extends object>(type: Type<T>, search: SearchType<T> = {}): Promise<Entity<T>[]> {
		// Custom search logic
	}
}

Registering the Custom Data Source

Once your custom DataSource is implemented, register it using the createDataSource function:

createDataSource({
	engine: __dirname + '/my-custom-data-source',
	someConfigOption: 'value'
})

Storage manager Functions API

createDataSource

createDataSource(config: object, dataSource: string = 'main'): DataSource

Creates and registers a new DataSource.

Parameters:

  • config: Configuration object for the data source.
  • dataSource: (Optional) Name of the data source. Defaults to 'main'.

Returns: The registered DataSource.

dataSource

dataSource(dataSource: string = 'main'): DataSource

Retrieves a registered DataSource by name.

ds

ds(dataSource: string = 'main'): DataSource

Alias for dataSource. Retrieves a registered DataSource by name.

Entity Types API

Entity

type Entity<T extends object = object> = T & { id: Identifier }

A model object linked to stored data though an Identifier.

Identifier

type Identifier = BigInt | Number | String

The identifier of the stored version of the model object. It is unique for each model object type.

MayEntity

type MayEntity<T extends object = object> = T | Entity<T>

A model object that may or may not be linked to stored data.

DataSource API

delete

delete(object: Entity<T>): Promise<T>

Deletes an entity from the storage.

Parameters:

  • object: The model object, as an Entity linked to a data source storage entry.

Returns: The object is returned without its Identifier because it no longer matches a stored Entity after deletion.

read

read(type: Type<T>, id: Identifier): Promise<Entity<T>>

Reads an Entity from the storage, by its identifier.

Parameters:

Returns: A promise resolving to the Entity read from storage.

readAll

readAll(type: Type<T>, options?: Options): Promise<Entity<T>[]>

Read all the stored entities.

Parameters:

readCollection

readCollection(object: Entity<T>, property: KeyOf<T>, type?: Type<PT>): Promise<Entity<PT>[]>

Reads a collection of related entities.

Parameters:

  • object: The Entity model object related to the collection to be read.
  • property: The name of the property linking to the collection.
  • type: (Optional) The class Type of the collection objects.

Returns: An array of Entity objects matching the property type.

save

save(object: MayEntity<T>): Promise<Entity<T>>

Saves an entity. If the object is not an Entity, it will be inserted into the storage and transformed into an Entity.

Parameters:

  • object: The model object to save into the storage.

Returns: The saved Entity.

search

search(type: Type<T>, search?: SearchType<T>, options?: Options): Promise<Entity<T>[]>

Searches for entities matching the criteria.

Parameters:

searchOne

searchOne(type: Type<T>, search?: SearchType<T>, options?: Options): Promise<Entity<T>[]>

Searches one entity matching the criteria.

It is recommended to use this function only with search criteria that represent a uniqueness constraint and match exactly one entity.

Parameters:

SearchType

export type SearchType<T extends object = object> = Partial<Record<KeyOf<T>, any>> & Record<string, any>

A SearchType is an object used to define search criteria for finding entities in the storage system. It maps property names of the target entity to the corresponding values to search for. This allows flexible and dynamic queries based on the properties and their expected values.

Result formatting options

Sort

import { Sort } from '@itrocks/data-source'

Use Sort or new Sort() to order results by the default sort order defined by the @Sort decorator.

Use new Sort(['property1', 'propertyN']) to order results by the values of the specified property paths.

Property paths prefixed with '-' will be sorted in descending order.

Example:

import { Sort } from '@itrocks/data-source'
import { User } from '@itrocks/user'

// (...)

// No sorting applied
const unsortedUsers = dataSource.readAll(User)

// Sorted by the default order defined with @Sort
const sortedUsers = dataSource.readAll(User, Sort)

// Sorted by email ascending, then identifier descending
const customSortUsers = dataSource.readAll(User, new Sort(['email', '-identifier']))

Planned Enhancements

  • Property Paths: In future versions, SearchType will support advanced search criteria using property paths. For example, to search for a User whose friends' birth city is "Paris": { 'friends.birthCity.name': 'Paris' }. This will simplify querying related objects.

  • Search Functions: The SearchType will also support functions for more complex criteria beyond simple equality. Examples include: { birthDate: duringYear(1976), age: greaterThan(48) }

Combining these features will be possible, such as: { 'friends.birthDate': before(new Date('1976-04-25')) }.