0.0.17 • Published 5 months ago

@itrocks/storage v0.0.17

Weekly downloads
-
License
LGPL-3.0-or-later
Repository
github
Last release
5 months ago

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.

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>): Promise<Entity<T>[]>

Searches for entities matching the criteria.

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.

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')) }.

0.0.17

5 months ago

0.0.16

7 months ago

0.0.15

7 months ago

0.0.14

7 months ago

0.0.13

7 months ago

0.0.12

7 months ago

0.0.11

9 months ago

0.0.10

9 months ago

0.0.9

9 months ago

0.0.8

9 months ago

0.0.7

9 months ago

0.0.6

9 months ago

0.0.5

9 months ago

0.0.4

9 months ago

0.0.3

9 months ago

0.0.2

9 months ago

0.0.1

9 months ago