Skip to content

Releases

ts-orm 2.0.0

Choose a tag to compare

@velkymx velkymx released this 15 Oct 16:52
d63448c

ts-orm v2.0.0

ts-orm v2.0.0 rewrites the internal query engine to eliminate runtime execution overhead while preserving total compile-time type safety.

This release targets high-concurrency Node.js and Bun applications where query compilation speed and low memory usage directly affect request throughput.

Key Changes

1. Re-Engineered Query Engine

  • Reduced query compilation overhead up to 4x compared to v1.x releases.
  • Consolidated internal AST parsing to minimize heap allocations per query execution.
  • Streamlined connection pool handling for lower latency under high concurrent load.

2. Strict Type Inference

  • Full autocomplete across complex multi-table joins, subqueries, and dynamic filters.
  • Payload shapes infer directly from schema definitions without requiring code generation steps or external CLI tools.
  • Schema mismatches and invalid relation references fail at build time.

3. Updated API Surface

  • Standardized initialization syntax for database drivers and custom dialects.
  • Cleaner methods for conditional filtering, pagination, and bulk mutations.
  • Uniform query semantics across supported SQL drivers.

Installation

npm install ts-orm@latest

1.5.0 Security-Focused Release

Choose a tag to compare

@velkymx velkymx released this 12 Dec 00:38
42b2418

⏺ Release Notes: v1.5.0

Security-Focused Release

Version 1.5.0 is a major security update that addresses critical vulnerabilities and adds enterprise-grade
security features to ts-orm. This release focuses on preventing SQL injection attacks, enhancing input
validation, and protecting sensitive information through error sanitization.


Highlights

  • SQL Injection Prevention: Hybrid validation and escaping for all database identifiers
  • Enhanced Validation: Strict format checking for UUID, datetime, date, and boolean types
  • Error Sanitization: Protected error messages prevent schema information leakage
  • Security Test Suite: 9 new tests covering injection attempts and validation edge cases

Security Enhancements

SQL Injection Prevention

  • ✅ All table names validated and escaped before query execution
  • ✅ All column names validated and escaped (WHERE, SET, ORDER BY, JOIN clauses)
  • ✅ Qualified identifiers (e.g., table.column) validated in JOIN operations
  • ✅ Hybrid approach: Pattern validation [a-zA-Z0-9_] + mysql2 escapeId()
  • ✅ Protection against common injection vectors:
    • Malicious table names: users; DROP TABLE users--
    • Malicious ORDER BY: id; DROP TABLE--
    • Malicious WHERE conditions: id' OR '1'='1

Enhanced Input Validation

  • ✅ UUID v4 format validation: Regex pattern
    /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
  • ✅ Datetime format validation: YYYY-MM-DD HH:MM:SS with range checks (month 1-12, day 1-31, hour 0-23,
    etc.)
  • ✅ Date format validation: YYYY-MM-DD with validity checks using Date object
  • ✅ Boolean type validation: Accepts true, false, 0, 1, '0', '1'
  • ✅ Enum null handling: Properly allows null/undefined for non-required enum fields
  • ✅ Required field fix: Now allows falsy values like false and 0 but rejects undefined/null

Error Sanitization

  • ✅ Database errors mapped to safe, generic messages
  • ✅ Full error details logged server-side with console.error()
  • ✅ Schema information never exposed to clients
  • ✅ Error mappings:
    • ER_DUP_ENTRY → "Record already exists"
    • ER_NO_REFERENCED_ROW → "Related record not found"
    • ER_ROW_IS_REFERENCED → "Cannot delete record - it is referenced by other records"
    • All other errors → "Database operation failed"

v1.4.0 Release

Choose a tag to compare

@velkymx velkymx released this 09 Apr 22:21

This release introduces a powerful new command-line tool that allows you to generate ts-orm JSON structs directly from your MySQL tables. It's the fastest way to bootstrap your project with real schema definitions.


New: CLI Struct Generator

You can now generate a ts-orm compatible struct with a single command:

npx ts-orm struct users

This will connect to your database using your .env settings and output a file called:

users.json

Features:

  • Maps MySQL types to ts-orm types (string, number, uuid, boolean, enum, date, datetime)
  • Detects auto_increment fields and marks them correctly
  • Extracts enum values as arrays
  • Assigns proper length limits for fields like varchar, date, and datetime
  • Skips optional or null defaults appropriately

Examples

MySQL column:

id INT AUTO_INCREMENT PRIMARY KEY

Generates:

{
  "name": "id",
  "type": "number",
  "required": true,
  "length": 11,
  "default": "auto_increment"
}

MySQL enum:

status ENUM('draft', 'published') NOT NULL DEFAULT 'draft'

Generates:

{
  "name": "status",
  "type": "enum",
  "required": true,
  "length": null,
  "default": "draft",
  "enum": ["draft", "published"]
}

Getting Started

npm install @velkymx/ts-orm
npx ts-orm struct users

This is especially useful when onboarding legacy tables or rapidly scaffolding new endpoints.


Thanks for using ts-orm. Feedback and feature suggestions welcome!

v1.3.0 – Auto-Increment Support & Validation

Choose a tag to compare

@velkymx velkymx released this 09 Apr 19:10

This release introduces support for traditional SQL-style AUTO_INCREMENT primary keys, with smarter insert handling, enhanced validation, and full test coverage.


🚀 New Features

✅ Auto-Increment ID Field Support

You can now define a struct field like this:

{
  name: "id",
  type: "number",
  required: true,
  length: 11,
  default: "auto_increment"
}

Behavior:

  • On create():
    • The id is ignored automatically (not included in SQL).
    • If the user tries to pass id, validation will fail.
  • On update() / remove():
    • The id is required and validated as a number.

🔐 Validation Enhancements

The validatePayload() function now:

  • Skips validation for auto_increment fields during insert
  • Rejects attempts to manually pass id during insert
  • Preserves strict type validation for updates/deletes

🧪 Tests Added

New tests verify:

  • Successful creation without ID
  • Proper update/delete using returned ID
  • Failure if user tries to provide an auto_increment ID on insert

✨ Example

await create('users', userStruct, {
  title: 'Auto User'
});
// Returns: { success: true, data: { id: 1 } }
await create('users', userStruct, {
  id: 99,
  title: 'Invalid'
});
// Fails: id should not be provided (auto_increment)

✅ Summary

This update adds:

  • Cleaner support for auto-incrementing numeric IDs
  • Safer inserts with validation against misuse
  • Consistent handling across all CRUD operations

v1.2.0 Release Notes

Choose a tag to compare

@velkymx velkymx released this 08 Apr 15:39

This release introduces powerful enhancements to the read and readWith methods by adding support for:

  • Sorting (orderBy, direction)
  • Pagination (limit, offset)

These features allow you to build cleaner APIs, faster admin tools, and scalable data listings with minimal effort.


New Features

1. Sorting Support

You can now sort results using orderBy and direction.

Usage:

await read('users', {}, {
  orderBy: 'created_at',
  direction: 'DESC'
});

2. Pagination Support

Limit the number of returned records and skip records using limit and offset.

Usage:

await read('posts', {}, {
  orderBy: 'created_at',
  direction: 'ASC',
  limit: 10,
  offset: 20  // Page 3, assuming 10 per page
});

3. readWith() Enhanced

The readWith method now also supports sorting and pagination across joined tables.

Usage:

await readWith('orders', {}, [
  { table: 'users', on: ['orders.user_id', 'users.id'], type: 'left' }
], {
  orderBy: 'orders.created_at',
  direction: 'DESC',
  limit: 5,
  offset: 10
});

Test Coverage

  • Bulk record inserts added for pagination simulation
  • New tests for:
    • read() with orderBy and limit/offset
    • readWith() with joins and pagination
  • Validated sorting direction and dataset correctness

Migration Notes

No breaking changes. Existing read() and readWith() calls will continue to work as before.

These new options are fully backward-compatible and optional.


What’s Next

  • Optional field selection (select)
  • Pagination metadata (total, pages)
  • Default sort support in struct definitions

Thank you for using ts-orm. Feedback and contributions welcome.

v1.1.0 Release Notes

Choose a tag to compare

@velkymx velkymx released this 08 Apr 15:29

This document outlines the latest additions to ts-orm for improved querying and relational data handling.


readOne

Fetch a single record that matches the given conditions.

Usage

const result = await readOne('users', { id: 'abc-123' });

if (result.success) {
  console.log('User:', result.data);
} else {
  console.log('Not found:', result.message);
}

Behavior

  • Returns { success: true, data: {...} } if found
  • Returns { success: false, data: null } if not found

findOrFail

Fetch a record by key or throw an error if it doesn't exist.

Usage

try {
  const user = await findOrFail('users', 'id', 'abc-123');
  console.log('User:', user);
} catch (err) {
  console.error(err.message); // Record not found in table 'users' with id = abc-123
}

Behavior

  • Returns the record directly if found
  • Throws Error if not found

readWith

Perform a SELECT query with JOINs based on JSON-configured relationships.

Syntax

readWith(table, conditions = {}, joins = [])

Usage

const result = await readWith('orders', { user_id: 42 }, [
  { table: 'users', on: ['orders.user_id', 'users.id'], type: 'inner' }
]);

if (result.success) {
  console.log(result.data);
}

Join Options

  • type (optional): 'inner' (default), 'left', 'right'
  • table: the table to join
  • on: an array of two column paths: [leftColumn, rightColumn]

Example

[
  { table: 'users', on: ['orders.user_id', 'users.id'], type: 'left' },
  { table: 'products', on: ['orders.product_id', 'products.id'], type: 'right' }
]

Behavior

  • Builds a raw SQL query with joins
  • Returns all joined results in result.data

Example Scenario with readWith

Two tables:

CREATE TABLE orders (
  id VARCHAR(36) PRIMARY KEY,
  user_id VARCHAR(36),
  product_id VARCHAR(36)
);

CREATE TABLE users (
  id VARCHAR(36) PRIMARY KEY,
  name VARCHAR(128)
);
const result = await readWith('orders', { user_id: 'abc-123' }, [
  { table: 'users', on: ['orders.user_id', 'users.id'], type: 'inner' }
]);

This performs:

SELECT * FROM orders
JOIN users ON orders.user_id = users.id
WHERE orders.user_id = 'abc-123'