CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-hibernatets

A TypeScript ORM library inspired by Hibernate for working with MySQL, MariaDB, and PostgreSQL databases using decorators and async/await patterns

Overview
Eval results
Files

data-operations.mddocs/

Data Operations

Core CRUD operations for loading, saving, and deleting entities with support for relationships, bulk operations, and advanced querying capabilities. HibernateTS provides a comprehensive set of functions for database interaction with full type safety.

Capabilities

Load Function

Loads entities from the database with support for deep loading, filtering, and flexible query patterns.

/**
 * Loads entities from the database with support for deep loading and filtering
 * @param findClass - Constructor class of the entity to load
 * @param primaryKeyOrFilter - Primary key, SQL condition, function filter, or LoadParams object
 * @param parameters - Array of SQL parameters or string parameter
 * @param options - LoadOptions for controlling loading behavior
 * @returns Promise resolving to single entity or array of entities
 */
function load<T>(findClass: ConstructorClass<T>, primaryKeyOrFilter: LoadParams<T, Filter<T>, { first: true } & CustomOmit<LoadOptions<T>, "first">>): Promise<T>;
function load<T>(findClass: ConstructorClass<T>, primaryKeyOrFilter: number | LoadParams<T, number>, parameters?: any[], options?: LoadOptions<T>): Promise<T>;
function load<T>(findClass: ConstructorClass<T>, primaryKeyOrFilter: string | SqlCondition | LoadParams<T, string>, parameters?: any[], options?: LoadOptions<T>): Promise<Array<T>>;
function load<T>(findClass: ConstructorClass<T>, primaryKeyOrFilter: ((obj: T) => any) | LoadParams<T, (obj: T) => any>, parameters?: any[], options?: LoadOptions<T>): Promise<Array<T>>;

interface LoadOptions<T> {
  /** Enable deep loading of relationships */
  deep?: boolean | Array<string | SqlCondition> | { [key: string]: string | SqlCondition | { filter: string | SqlCondition, depths: number } };
  /** Array of field names to skip during loading */
  skipFields?: Array<string>;
  /** Return single result instead of array */
  first?: boolean;
  /** Include IDs for non-deep one-to-one relationships */
  idOnNonDeepOneToOne?: boolean;
  /** Include shallow reference data */
  withShallowReferences?: boolean;
  /** Database connection to use */
  db?: DataBaseBase;
  /** Skip automatic setter interception */
  dontInterceptSetters?: true;
  /** Enable array function interception */
  interceptArrayFunctions?: boolean;
}

interface LoadParams<T, F = Filter<T>, O = LoadOptions<T>> {
  /** Filter condition */
  filter?: F;
  /** SQL parameters */
  params?: Array<string | number> | string;
  /** Load options */
  options?: O;
}

interface ConstructorClass<T> {
  new (...args: any[]): T;
}

interface DataBaseBase {
  sqlquery<T>(cfg: any, queryString: string, params?: any[]): Promise<any>;
  selectQuery<T>(queryString: string, params?: any[]): Promise<Array<T>>;
  end(): Promise<void>;
}

type Filter<T> = SqlCondition | string | number | ((obj: T) => any);

Usage Examples:

import { load, SqlCondition } from "hibernatets";

// Load by primary key
const user = await load(User, 1);

// Load by primary key with relationships
const userWithPosts = await load(User, 1, [], { deep: true });

// Load multiple users with SQL condition
const activeUsers = await load(User,
  new SqlCondition().column("active").equals(true)
);

// Load with specific deep loading
const userWithFilteredPosts = await load(User, 1, [], {
  deep: {
    posts: new SqlCondition().column("published").equals(true)
  }
});

// Load with function filter
const youngUsers = await load(User, (user: User) => user.age < 30);

// Load with LoadParams object
const result = await load(User, {
  filter: new SqlCondition().column("name").equals("Alice"),
  params: [],
  options: { deep: true, first: true }
});

// Load with skip fields
const usersWithoutSensitiveData = await load(User,
  SqlCondition.ALL,
  [],
  { skipFields: ["password", "email"] }
);

Save Function

Saves entities to the database with support for relationships, duplicate key handling, and bulk operations.

/**
 * Saves entities to the database with support for relationships and duplicate key handling
 * @param saveObjects - Single entity or array of entities to save
 * @param options - SaveOptions including updateOnDuplicate and db connection
 * @returns Promise resolving to array of affected row counts
 */
function save<T>(saveObjects: T | T[], options?: SaveOptions<T>): Promise<Array<number>>;

interface SaveOptions<T> {
  /** Handle duplicate keys during save operation */
  updateOnDuplicate?: boolean | { skip?: Array<keyof T & string> };
  /** Database connection to use */
  db?: DataBaseBase;
}

Usage Examples:

import { save } from "hibernatets";

// Save single entity
const user = new User();
user.name = "Alice";
user.email = "alice@example.com";
const [insertId] = await save(user);

// Save multiple entities
const users = [
  Object.assign(new User(), { name: "Bob", email: "bob@example.com" }),
  Object.assign(new User(), { name: "Charlie", email: "charlie@example.com" })
];
const insertIds = await save(users);

// Save with duplicate key handling
await save(user, {
  updateOnDuplicate: true
});

// Save with selective duplicate key handling
await save(user, {
  updateOnDuplicate: { skip: ["createdAt", "id"] }
});

// Save with relationships
const userWithPosts = new User();
userWithPosts.name = "David";
userWithPosts.posts = [
  Object.assign(new Post(), { title: "First Post" }),
  Object.assign(new Post(), { title: "Second Post" })
];
await save(userWithPosts);

Delete Function

Deletes entities from the database with support for cascade deletion and bulk operations.

/**
 * Deletes entities from the database with support for cascade deletion
 * @param object - Entity instance to delete
 * @param opts - DeleteOptions including cascade deletion settings
 * @returns Promise resolving to number of affected rows
 */
function remove<T>(object: any, opts?: DeleteOptions): Promise<number>;

/**
 * Deletes entities by primary key with support for bulk deletion
 * @param descriptor - Constructor class of the entity
 * @param primaryId - Primary key value or array of values
 * @param opts - DeleteOptions including cascade deletion settings
 * @returns Promise resolving to number of affected rows
 */
function remove<T>(descriptor: ConstructorClass<T>, primaryId: number | Array<number>, opts?: DeleteOptions): Promise<number>;

interface DeleteOptions {
  /** Enable cascade deletion of related entities */
  deep?: boolean | Array<string>;
  /** Database connection to use */
  db?: DataBaseBase;
}

Usage Examples:

import { remove, load } from "hibernatets";

// Delete single entity
const user = await load(User, 1);
const deletedRows = await remove(user);

// Delete by primary key
const deletedCount = await remove(User, 1);

// Delete multiple entities by IDs
const deletedCount = await remove(User, [1, 2, 3]);

// Cascade deletion of related entities
await remove(user, { deep: true });

// Selective cascade deletion
await remove(user, {
  deep: ["posts", "profile"]
});

Array Management

Functions for managing array relationships and bulk operations.

/**
 * Adds items to an array property with automatic relationship mapping
 * @param parent - Parent entity containing the array
 * @param key - Key of the array property
 * @param opts - Array of items to add or AddArrayOpts object
 */
function addArrayItem<T extends ISaveAbleObject, K extends ArrayKeys<T>>(
  parent: T,
  key: K,
  opts: Array<ArrayType<T, K> & ISaveAbleObject> | AddArrayOpts<ArrayType<T, K> & ISaveAbleObject>
): void;

interface AddArrayOpts<T> {
  /** Database connection to use */
  db: DataBaseBase;
  /** Items to add to the array */
  items: Array<T>;
}

interface ISaveAbleObject {
  [key: string]: any;
}

type ArrayKeys<T> = {
  [K in keyof T]: T[K] extends Array<infer U> ? K : never;
}[keyof T];

type ArrayType<T, K extends keyof T> = T[K] extends Array<infer U> ? U : never;

Usage Examples:

import { addArrayItem, load, save } from "hibernatets";

// Load user with posts
const user = await load(User, 1, [], { deep: true });

// Add new posts to user
const newPosts = [
  Object.assign(new Post(), { title: "New Post 1" }),
  Object.assign(new Post(), { title: "New Post 2" })
];

addArrayItem(user, "posts", newPosts);

// Save to persist changes
await save(user);

Query Execution

Execute pending database updates and retrieve results.

/**
 * Executes all pending database updates for an object and returns results
 * @param object - Entity with pending updates
 * @returns Promise resolving to array of result counts
 */
function queries(object: any): Promise<Array<number>>;

Usage Examples:

import { queries, intercept } from "hibernatets";

// Enable automatic change tracking
const user = await load(User, 1);
intercept(user);

// Make changes
user.name = "Updated Name";
user.email = "updated@example.com";

// Execute all pending queries
const results = await queries(user);
console.log(`Updated ${results.length} database records`);

Advanced Loading Patterns

Complex loading scenarios with conditional relationships and custom filters.

import { load, SqlCondition, Mappings } from "hibernatets";

// Conditional deep loading based on user permissions
async function loadUserData(userId: number, includePrivateData: boolean) {
  const loadOptions = {
    deep: includePrivateData ? true : ["posts"],
    skipFields: includePrivateData ? [] : ["email", "phone"]
  };

  return await load(User, userId, [], loadOptions);
}

// Load with complex relationship filters
const usersWithRecentPosts = await load(User, SqlCondition.ALL, [], {
  deep: {
    posts: new SqlCondition()
      .column("createdAt")
      .greater()
      .param(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)) // Last 30 days
  }
});

// Pagination with relationships
async function getPaginatedUsers(page: number, pageSize: number) {
  const offset = page * pageSize;

  return await load(User,
    new SqlCondition()
      .column("active")
      .equals(true)
      .and(c => c.column("id").greater().param(offset)),
    [],
    {
      deep: ["profile"],
      first: false
    }
  );
}

Bulk Operations

Efficient patterns for handling large datasets and bulk operations.

import { save, load, remove } from "hibernatets";

// Bulk insert with batch processing
async function bulkInsertUsers(userData: any[]) {
  const batchSize = 100;
  const results = [];

  for (let i = 0; i < userData.length; i += batchSize) {
    const batch = userData.slice(i, i + batchSize);
    const users = batch.map(data => Object.assign(new User(), data));
    const batchResults = await save(users);
    results.push(...batchResults);
  }

  return results;
}

// Bulk update with selective fields
async function bulkUpdateUserStatus(userIds: number[], newStatus: boolean) {
  const users = await load(User,
    new SqlCondition().column("id").equals(userIds)
  );

  users.forEach(user => {
    user.active = newStatus;
    user.lastModified = new Date();
  });

  return await save(users, {
    updateOnDuplicate: { skip: ["createdAt"] }
  });
}

// Bulk delete with conditions
async function cleanupInactiveUsers(daysInactive: number) {
  const cutoffDate = new Date(Date.now() - daysInactive * 24 * 60 * 60 * 1000);

  const inactiveUsers = await load(User,
    new SqlCondition()
      .column("lastLoginAt")
      .smaller()
      .param(cutoffDate)
      .and(c => c.column("active").equals(false))
  );

  const deletePromises = inactiveUsers.map(user =>
    remove(user, { deep: ["posts", "profile"] })
  );

  return await Promise.all(deletePromises);
}

Install with Tessl CLI

npx tessl i tessl/npm-hibernatets

docs

configuration.md

data-operations.md

database-adapters.md

entity-modeling.md

index.md

sql-conditions.md

tile.json