@tstdl/base 0.93.139 → 0.93.141
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -0
- package/ai/genkit/multi-region.plugin.js +5 -3
- package/ai/genkit/tests/multi-region.test.d.ts +1 -0
- package/ai/genkit/tests/multi-region.test.js +5 -2
- package/ai/parser/parser.js +2 -2
- package/ai/prompts/build.js +1 -0
- package/ai/prompts/instructions-formatter.d.ts +15 -2
- package/ai/prompts/instructions-formatter.js +36 -31
- package/ai/prompts/prompt-builder.js +5 -5
- package/ai/prompts/steering.d.ts +3 -2
- package/ai/prompts/steering.js +3 -1
- package/ai/tests/instructions-formatter.test.js +1 -0
- package/api/README.md +403 -0
- package/api/client/client.js +7 -13
- package/api/client/tests/api-client.test.js +10 -10
- package/api/default-error-handlers.js +1 -1
- package/api/response.d.ts +2 -2
- package/api/response.js +22 -33
- package/api/server/api-controller.d.ts +1 -1
- package/api/server/api-controller.js +3 -3
- package/api/server/api-request-token.provider.d.ts +1 -0
- package/api/server/api-request-token.provider.js +1 -0
- package/api/server/middlewares/allowed-methods.middleware.js +2 -1
- package/api/server/middlewares/content-type.middleware.js +2 -1
- package/api/types.d.ts +3 -2
- package/application/README.md +240 -0
- package/application/application.d.ts +1 -1
- package/application/application.js +3 -3
- package/application/providers.d.ts +20 -2
- package/application/providers.js +34 -7
- package/audit/README.md +267 -0
- package/audit/module.d.ts +5 -0
- package/audit/module.js +9 -1
- package/authentication/README.md +288 -0
- package/authentication/client/authentication.service.d.ts +12 -11
- package/authentication/client/authentication.service.js +21 -21
- package/authentication/client/http-client.middleware.js +2 -2
- package/authentication/server/module.d.ts +5 -0
- package/authentication/server/module.js +9 -1
- package/authentication/tests/authentication.api-controller.test.js +1 -1
- package/authentication/tests/authentication.api-request-token.provider.test.js +1 -1
- package/authentication/tests/authentication.client-error-handling.test.js +2 -1
- package/authentication/tests/authentication.client-service-refresh.test.js +5 -3
- package/authentication/tests/authentication.client-service.test.js +1 -1
- package/browser/README.md +401 -0
- package/cancellation/README.md +156 -0
- package/cancellation/tests/coverage.test.d.ts +1 -0
- package/cancellation/tests/coverage.test.js +49 -0
- package/cancellation/tests/leak.test.js +24 -29
- package/cancellation/tests/token.test.d.ts +1 -0
- package/cancellation/tests/token.test.js +136 -0
- package/cancellation/token.d.ts +53 -177
- package/cancellation/token.js +132 -208
- package/circuit-breaker/postgres/module.d.ts +1 -0
- package/circuit-breaker/postgres/module.js +5 -1
- package/context/README.md +174 -0
- package/cookie/README.md +161 -0
- package/css/README.md +157 -0
- package/data-structures/README.md +320 -0
- package/decorators/README.md +140 -0
- package/distributed-loop/README.md +231 -0
- package/distributed-loop/distributed-loop.js +1 -1
- package/document-management/README.md +403 -0
- package/document-management/server/configure.js +5 -1
- package/document-management/server/module.d.ts +1 -1
- package/document-management/server/module.js +1 -1
- package/document-management/server/services/document-management-ancillary.service.js +1 -1
- package/document-management/server/services/document-management.service.js +9 -7
- package/document-management/tests/ai-config-hierarchy.test.js +0 -5
- package/document-management/tests/document-management-ai-overrides.test.js +0 -1
- package/document-management/tests/document-management-core.test.js +2 -7
- package/document-management/tests/document-management.api.test.js +6 -7
- package/document-management/tests/document-statistics.service.test.js +11 -12
- package/document-management/tests/document-validation-ai-overrides.test.js +0 -1
- package/document-management/tests/document.service.test.js +3 -3
- package/document-management/tests/enum-helpers.test.js +2 -3
- package/dom/README.md +213 -0
- package/enumerable/README.md +259 -0
- package/enumeration/README.md +121 -0
- package/errors/README.md +267 -0
- package/examples/document-management/main.d.ts +1 -0
- package/examples/document-management/main.js +14 -11
- package/file/README.md +191 -0
- package/formats/README.md +210 -0
- package/function/README.md +144 -0
- package/http/README.md +318 -0
- package/http/client/adapters/undici.adapter.js +1 -1
- package/http/client/http-client-request.d.ts +6 -5
- package/http/client/http-client-request.js +8 -9
- package/http/server/node/node-http-server.js +1 -2
- package/image-service/README.md +137 -0
- package/injector/README.md +491 -0
- package/intl/README.md +113 -0
- package/json-path/README.md +182 -0
- package/jsx/README.md +154 -0
- package/key-value-store/README.md +191 -0
- package/key-value-store/postgres/module.d.ts +1 -0
- package/key-value-store/postgres/module.js +5 -1
- package/lock/README.md +249 -0
- package/lock/postgres/module.d.ts +1 -0
- package/lock/postgres/module.js +5 -1
- package/lock/web/web-lock.js +119 -47
- package/logger/README.md +287 -0
- package/mail/README.md +256 -0
- package/mail/module.d.ts +5 -1
- package/mail/module.js +11 -6
- package/memory/README.md +144 -0
- package/message-bus/README.md +244 -0
- package/message-bus/message-bus-base.js +1 -1
- package/module/README.md +182 -0
- package/module/module.d.ts +1 -1
- package/module/module.js +77 -17
- package/module/modules/web-server.module.js +3 -4
- package/notification/server/module.d.ts +1 -0
- package/notification/server/module.js +5 -1
- package/notification/tests/notification-flow.test.js +2 -2
- package/notification/tests/notification-type.service.test.js +24 -15
- package/object-storage/README.md +300 -0
- package/openid-connect/README.md +274 -0
- package/orm/README.md +423 -0
- package/orm/decorators.d.ts +5 -1
- package/orm/decorators.js +1 -1
- package/orm/server/drizzle/schema-converter.js +17 -30
- package/orm/server/encryption.d.ts +0 -1
- package/orm/server/encryption.js +1 -4
- package/orm/server/index.d.ts +1 -6
- package/orm/server/index.js +1 -6
- package/orm/server/migration.d.ts +19 -0
- package/orm/server/migration.js +72 -0
- package/orm/server/repository.d.ts +1 -1
- package/orm/server/transaction.d.ts +5 -10
- package/orm/server/transaction.js +22 -26
- package/orm/server/transactional.js +3 -3
- package/orm/tests/database-migration.test.d.ts +1 -0
- package/orm/tests/database-migration.test.js +82 -0
- package/orm/tests/encryption.test.js +3 -4
- package/orm/utils.d.ts +17 -2
- package/orm/utils.js +49 -1
- package/package.json +9 -6
- package/password/README.md +164 -0
- package/pdf/README.md +246 -0
- package/polyfills.js +1 -0
- package/pool/README.md +198 -0
- package/process/README.md +237 -0
- package/promise/README.md +252 -0
- package/promise/cancelable-promise.js +1 -1
- package/random/README.md +193 -0
- package/rate-limit/postgres/module.d.ts +1 -0
- package/rate-limit/postgres/module.js +5 -1
- package/reflection/README.md +305 -0
- package/reflection/decorator-data.js +11 -12
- package/rpc/README.md +386 -0
- package/rxjs-utils/README.md +262 -0
- package/schema/README.md +342 -0
- package/serializer/README.md +342 -0
- package/signals/implementation/README.md +134 -0
- package/sse/README.md +278 -0
- package/task-queue/README.md +293 -0
- package/task-queue/postgres/drizzle/{0000_simple_invisible_woman.sql → 0000_wakeful_sunspot.sql} +22 -14
- package/task-queue/postgres/drizzle/meta/0000_snapshot.json +160 -82
- package/task-queue/postgres/drizzle/meta/_journal.json +2 -2
- package/task-queue/postgres/module.d.ts +1 -0
- package/task-queue/postgres/module.js +5 -1
- package/task-queue/postgres/schemas.d.ts +9 -6
- package/task-queue/postgres/schemas.js +4 -3
- package/task-queue/postgres/task-queue.d.ts +4 -13
- package/task-queue/postgres/task-queue.js +462 -355
- package/task-queue/postgres/task.model.d.ts +12 -5
- package/task-queue/postgres/task.model.js +51 -25
- package/task-queue/task-context.d.ts +2 -2
- package/task-queue/task-context.js +8 -8
- package/task-queue/task-queue.d.ts +53 -19
- package/task-queue/task-queue.js +121 -55
- package/task-queue/tests/cascading-cancellations.test.d.ts +1 -0
- package/task-queue/tests/cascading-cancellations.test.js +38 -0
- package/task-queue/tests/complex.test.js +45 -229
- package/task-queue/tests/coverage-branch.test.d.ts +1 -0
- package/task-queue/tests/coverage-branch.test.js +407 -0
- package/task-queue/tests/coverage-enhancement.test.d.ts +1 -0
- package/task-queue/tests/coverage-enhancement.test.js +144 -0
- package/task-queue/tests/dag-dependencies.test.d.ts +1 -0
- package/task-queue/tests/dag-dependencies.test.js +41 -0
- package/task-queue/tests/dependencies.test.js +28 -26
- package/task-queue/tests/extensive-dependencies.test.js +64 -139
- package/task-queue/tests/fan-out-spawning.test.d.ts +1 -0
- package/task-queue/tests/fan-out-spawning.test.js +53 -0
- package/task-queue/tests/idempotent-replacement.test.d.ts +1 -0
- package/task-queue/tests/idempotent-replacement.test.js +61 -0
- package/task-queue/tests/missing-idempotent-tasks.test.d.ts +1 -0
- package/task-queue/tests/missing-idempotent-tasks.test.js +38 -0
- package/task-queue/tests/queue.test.js +128 -8
- package/task-queue/tests/worker.test.js +39 -16
- package/task-queue/tests/zombie-parent.test.d.ts +1 -0
- package/task-queue/tests/zombie-parent.test.js +45 -0
- package/task-queue/tests/zombie-recovery.test.d.ts +1 -0
- package/task-queue/tests/zombie-recovery.test.js +51 -0
- package/templates/README.md +287 -0
- package/test5.js +5 -5
- package/testing/README.md +157 -0
- package/testing/integration-setup.d.ts +4 -4
- package/testing/integration-setup.js +54 -29
- package/text/README.md +346 -0
- package/text/localization.service.js +2 -2
- package/threading/README.md +238 -0
- package/types/README.md +311 -0
- package/utils/README.md +322 -0
- package/utils/async-iterable-helpers/observable-iterable.d.ts +1 -1
- package/utils/async-iterable-helpers/observable-iterable.js +4 -8
- package/utils/async-iterable-helpers/take-until.js +4 -4
- package/utils/backoff.js +89 -30
- package/utils/file-reader.js +1 -2
- package/utils/retry-with-backoff.js +1 -1
- package/utils/timer.d.ts +1 -1
- package/utils/timer.js +5 -7
- package/utils/timing.d.ts +1 -1
- package/utils/timing.js +2 -4
- package/utils/z-base32.d.ts +1 -0
- package/utils/z-base32.js +1 -0
package/orm/README.md
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
# ORM Module
|
|
2
|
+
|
|
3
|
+
A robust, code-first Object-Relational Mapping (ORM) library for PostgreSQL, built on top of [Drizzle ORM](https://orm.drizzle.team/). It simplifies data access through a repository pattern, provides advanced type-safe querying (including full-text search and ParadeDB integration), and integrates seamlessly with the dependency injection system.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [✨ Features](#-features)
|
|
8
|
+
- [Core Concepts](#core-concepts)
|
|
9
|
+
- [Entities](#entities)
|
|
10
|
+
- [Repositories](#repositories)
|
|
11
|
+
- [Decorators](#decorators)
|
|
12
|
+
- [Querying](#querying)
|
|
13
|
+
- [Transactions](#transactions)
|
|
14
|
+
- [🚀 Basic Usage](#-basic-usage)
|
|
15
|
+
- [1. Configuration](#1-configuration)
|
|
16
|
+
- [2. Defining Entities](#2-defining-entities)
|
|
17
|
+
- [3. Using Repositories](#3-using-repositories)
|
|
18
|
+
- [🔧 Advanced Topics](#-advanced-topics)
|
|
19
|
+
- [Full-Text Search](#full-text-search)
|
|
20
|
+
- [ParadeDB Integration](#paradedb-integration)
|
|
21
|
+
- [Transparent Encryption](#transparent-encryption)
|
|
22
|
+
- [Automatic Expiration (TTL)](#automatic-expiration-ttl)
|
|
23
|
+
- [Embedded Properties](#embedded-properties)
|
|
24
|
+
- [Transactions](#transaction-management)
|
|
25
|
+
- [Soft Deletes](#soft-deletes)
|
|
26
|
+
- [SQL Helper Functions](#sql-helper-functions)
|
|
27
|
+
- [📚 API](#-api)
|
|
28
|
+
|
|
29
|
+
## ✨ Features
|
|
30
|
+
|
|
31
|
+
- **Code-First Schema**: Define database tables, columns, and relationships using TypeScript classes and decorators.
|
|
32
|
+
- **Repository Pattern**: Standardized API for CRUD operations, bulk actions, and complex querying.
|
|
33
|
+
- **Type-Safe Querying**: MongoDB-like query syntax (`$eq`, `$gt`, `$in`, `$or`) fully typed to your entities.
|
|
34
|
+
- **Advanced Search**: Built-in support for PostgreSQL `tsvector`, `pg_trgm`, and ParadeDB (`bm25`) full-text search.
|
|
35
|
+
- **Transparent Encryption**: Encrypt sensitive columns automatically at the application level using AES-GCM.
|
|
36
|
+
- **Automatic Expiration**: Built-in Time-To-Live (TTL) support for auto-deleting old records.
|
|
37
|
+
- **Transaction Management**: Robust transaction handling with automatic commit/rollback and context propagation.
|
|
38
|
+
- **Soft Deletes**: Built-in support for soft deletion when using the standard `Entity` base class.
|
|
39
|
+
- **Dependency Injection**: Seamless integration with `@tstdl/base/injector`.
|
|
40
|
+
|
|
41
|
+
## Core Concepts
|
|
42
|
+
|
|
43
|
+
### Entities
|
|
44
|
+
|
|
45
|
+
Entities are classes that map directly to database tables. The module provides base classes to standardize common fields:
|
|
46
|
+
|
|
47
|
+
- **`Entity`**: The standard base class. Includes an `id` (UUIDv7 primary key) and metadata fields: `revision`, `createTimestamp`, `deleteTimestamp` (for soft deletes), and `attributes` (JSONB).
|
|
48
|
+
- **`BaseEntity`**: A minimal base class providing only the `id` primary key. Useful for join tables or simple configuration data.
|
|
49
|
+
- **`TenantEntity`**: Extends `Entity` with a `tenantId` column for multi-tenant applications.
|
|
50
|
+
|
|
51
|
+
### Repositories
|
|
52
|
+
|
|
53
|
+
Repositories provide the interface to the database.
|
|
54
|
+
|
|
55
|
+
- **`EntityRepository<T>`**: The generic class providing methods like `load`, `insert`, `update`, `search`, etc.
|
|
56
|
+
- **`injectRepository(Entity)`**: Helper to inject the default repository for an entity.
|
|
57
|
+
- **`getRepository(Entity)`**: Helper to create a custom repository class extending the base functionality.
|
|
58
|
+
|
|
59
|
+
### Decorators
|
|
60
|
+
|
|
61
|
+
Decorators configure the mapping between TypeScript properties and database columns/constraints.
|
|
62
|
+
|
|
63
|
+
- **Class**: `@Table`, `@Index`, `@Unique`, `@Check`, `@ParadeIndex`, `@TimeToLive`.
|
|
64
|
+
- **Property**: `@StringProperty`, `@Integer`, `@UuidProperty`, `@TimestampProperty`, `@EncryptedProperty`, `@References`, `@EmbeddedProperty`, `@GeneratedTsVector`, `@TrigramIndex`.
|
|
65
|
+
|
|
66
|
+
### Querying
|
|
67
|
+
|
|
68
|
+
The ORM uses a structured query object syntax instead of raw SQL builders for most operations.
|
|
69
|
+
|
|
70
|
+
- **Comparison**: `$eq`, `$neq`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$regex`.
|
|
71
|
+
- **Logical**: `$and`, `$or`, `$nor`, `$not`.
|
|
72
|
+
- **Search**: `$tsvector`, `$trigram`, `$parade`.
|
|
73
|
+
|
|
74
|
+
### Transactions
|
|
75
|
+
|
|
76
|
+
The `Transactional` base class allows services to manage transactions easily.
|
|
77
|
+
|
|
78
|
+
- **`this.transaction(async (tx) => { ... })`**: Starts a transaction scope.
|
|
79
|
+
- **`repository.withTransaction(tx)`**: Binds a repository to an active transaction.
|
|
80
|
+
|
|
81
|
+
## 🚀 Basic Usage
|
|
82
|
+
|
|
83
|
+
### 1. Configuration
|
|
84
|
+
|
|
85
|
+
Configure the ORM in your application bootstrap.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { configureOrm } from '@tstdl/base/orm/server';
|
|
89
|
+
|
|
90
|
+
configureOrm({
|
|
91
|
+
connection: {
|
|
92
|
+
host: 'localhost',
|
|
93
|
+
port: 5432,
|
|
94
|
+
user: 'postgres',
|
|
95
|
+
password: 'password',
|
|
96
|
+
database: 'my_app',
|
|
97
|
+
},
|
|
98
|
+
// Optional: Secret for column encryption (32 bytes)
|
|
99
|
+
encryptionSecret: new Uint8Array([
|
|
100
|
+
/* ... 32 bytes ... */
|
|
101
|
+
]),
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2. Defining Entities
|
|
106
|
+
|
|
107
|
+
Define your data model using classes and decorators. Note that standard schema decorators (like `@StringProperty`) are combined with ORM-specific decorators.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { Entity, Table, Unique, References } from '@tstdl/base/orm';
|
|
111
|
+
import { UuidProperty } from '@tstdl/base/orm/schemas';
|
|
112
|
+
import { StringProperty } from '@tstdl/base/schema';
|
|
113
|
+
|
|
114
|
+
@Table({ name: 'users' })
|
|
115
|
+
export class User extends Entity {
|
|
116
|
+
@StringProperty()
|
|
117
|
+
name: string;
|
|
118
|
+
|
|
119
|
+
@StringProperty()
|
|
120
|
+
@Unique()
|
|
121
|
+
email: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@Table({ name: 'posts' })
|
|
125
|
+
export class Post extends Entity {
|
|
126
|
+
@StringProperty()
|
|
127
|
+
title: string;
|
|
128
|
+
|
|
129
|
+
@UuidProperty()
|
|
130
|
+
@References(() => User)
|
|
131
|
+
authorId: string;
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 3. Using Repositories
|
|
136
|
+
|
|
137
|
+
Inject repositories into your services to interact with the database.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { Singleton } from '@tstdl/base/injector';
|
|
141
|
+
import { injectRepository, Transactional } from '@tstdl/base/orm/server';
|
|
142
|
+
import { User } from './user.model.js';
|
|
143
|
+
|
|
144
|
+
@Singleton()
|
|
145
|
+
export class UserService extends Transactional {
|
|
146
|
+
// Inject the default repository for User
|
|
147
|
+
readonly #userRepository = injectRepository(User);
|
|
148
|
+
|
|
149
|
+
async createUser(name: string, email: string): Promise<User> {
|
|
150
|
+
// Insert a new entity
|
|
151
|
+
return await this.#userRepository.insert({
|
|
152
|
+
name,
|
|
153
|
+
email,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async findByEmail(email: string): Promise<User | undefined> {
|
|
158
|
+
// Query using the object syntax
|
|
159
|
+
return await this.#userRepository.tryLoadByQuery({
|
|
160
|
+
email: { $eq: email },
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async updateName(id: string, newName: string): Promise<void> {
|
|
165
|
+
// Update specific fields
|
|
166
|
+
await this.#userRepository.update(id, {
|
|
167
|
+
name: newName,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 🔧 Advanced Topics
|
|
174
|
+
|
|
175
|
+
### Full-Text Search
|
|
176
|
+
|
|
177
|
+
The ORM supports PostgreSQL's native full-text search (`tsvector`) and trigram similarity (`pg_trgm`).
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { Entity, Table, GeneratedTsVector } from '@tstdl/base/orm';
|
|
181
|
+
import { StringProperty } from '@tstdl/base/schema';
|
|
182
|
+
|
|
183
|
+
@Table({ name: 'articles' })
|
|
184
|
+
export class Article extends Entity {
|
|
185
|
+
@StringProperty()
|
|
186
|
+
title: string;
|
|
187
|
+
|
|
188
|
+
@StringProperty()
|
|
189
|
+
content: string;
|
|
190
|
+
|
|
191
|
+
// Automatically generated tsvector column combining title (weight A) and content (weight B)
|
|
192
|
+
@GeneratedTsVector({
|
|
193
|
+
sources: ['title', 'content'],
|
|
194
|
+
weights: { title: 'A', content: 'B' },
|
|
195
|
+
language: 'english',
|
|
196
|
+
})
|
|
197
|
+
searchVector: string;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// In your service:
|
|
201
|
+
const results = await articleRepository.search({
|
|
202
|
+
query: {
|
|
203
|
+
$tsvector: {
|
|
204
|
+
fields: ['searchVector'],
|
|
205
|
+
query: 'typescript & orm',
|
|
206
|
+
language: 'english',
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
highlight: 'content', // Optional: highlight matches in content
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### ParadeDB Integration
|
|
214
|
+
|
|
215
|
+
If you are using [ParadeDB](https://www.paradedb.com/), you can use the `@ParadeIndex` decorator for BM25 relevance scoring and advanced search capabilities.
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
import { Entity, Table, ParadeIndex } from '@tstdl/base/orm';
|
|
219
|
+
import { StringProperty } from '@tstdl/base/schema';
|
|
220
|
+
|
|
221
|
+
@Table({ name: 'products' })
|
|
222
|
+
@ParadeIndex({
|
|
223
|
+
// Define a BM25 index on these columns
|
|
224
|
+
columns: ['name', 'description'],
|
|
225
|
+
})
|
|
226
|
+
export class Product extends Entity {
|
|
227
|
+
@StringProperty()
|
|
228
|
+
name: string;
|
|
229
|
+
|
|
230
|
+
@StringProperty()
|
|
231
|
+
description: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Searching with ParadeDB
|
|
235
|
+
const results = await productRepository.search({
|
|
236
|
+
query: {
|
|
237
|
+
$parade: {
|
|
238
|
+
fields: ['name', 'description'],
|
|
239
|
+
query: 'shoes OR boots',
|
|
240
|
+
distance: 1, // Fuzzy matching
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Transparent Encryption
|
|
247
|
+
|
|
248
|
+
Encrypt sensitive data at rest using the `@EncryptedProperty` decorator. The data is automatically encrypted on insert/update and decrypted on load. The underlying database column type will be `bytea`.
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { Entity, EncryptedProperty } from '@tstdl/base/orm';
|
|
252
|
+
import { StringProperty } from '@tstdl/base/schema';
|
|
253
|
+
|
|
254
|
+
export class UserSecret extends Entity {
|
|
255
|
+
@StringProperty()
|
|
256
|
+
@EncryptedProperty()
|
|
257
|
+
apiKey: string;
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Automatic Expiration (TTL)
|
|
262
|
+
|
|
263
|
+
Automatically delete records after a specified duration. This relies on the `createTimestamp` field of `Entity` or a specific property marked with `@Expires`.
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { Entity, TimeToLive, Expires } from '@tstdl/base/orm';
|
|
267
|
+
import { TimestampProperty } from '@tstdl/base/orm/schemas';
|
|
268
|
+
|
|
269
|
+
// Soft delete records 24 hours after creation
|
|
270
|
+
@TimeToLive(24 * 60 * 60 * 1000, 'soft')
|
|
271
|
+
export class Session extends Entity {
|
|
272
|
+
// ...
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Or expire based on a specific column
|
|
276
|
+
export class ApiKey extends Entity {
|
|
277
|
+
@TimestampProperty()
|
|
278
|
+
@Expires({ after: 0, mode: 'hard' }) // Hard delete immediately when validUntil is reached
|
|
279
|
+
validUntil: number;
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Embedded Properties
|
|
284
|
+
|
|
285
|
+
Group related columns into a reusable class and embed them into entities. This flattens the structure in the database table but keeps it structured in your code.
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import { Entity, EmbeddedProperty } from '@tstdl/base/orm';
|
|
289
|
+
import { StringProperty } from '@tstdl/base/schema';
|
|
290
|
+
|
|
291
|
+
class Address {
|
|
292
|
+
@StringProperty()
|
|
293
|
+
street: string;
|
|
294
|
+
|
|
295
|
+
@StringProperty()
|
|
296
|
+
city: string;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export class User extends Entity {
|
|
300
|
+
@EmbeddedProperty(Address, { prefix: 'billing_' })
|
|
301
|
+
billingAddress: Address; // DB Columns: billing_street, billing_city
|
|
302
|
+
|
|
303
|
+
@EmbeddedProperty(Address, { prefix: 'shipping_' })
|
|
304
|
+
shippingAddress: Address; // DB Columns: shipping_street, shipping_city
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Transaction Management
|
|
309
|
+
|
|
310
|
+
Services extending `Transactional` can manage transactions. The repository automatically participates in the active transaction context.
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
@Singleton()
|
|
314
|
+
export class OrderService extends Transactional {
|
|
315
|
+
readonly #orderRepository = injectRepository(Order);
|
|
316
|
+
readonly #itemRepository = injectRepository(OrderItem);
|
|
317
|
+
|
|
318
|
+
async createOrder(data: OrderData): Promise<void> {
|
|
319
|
+
// Start a transaction scope
|
|
320
|
+
await this.transaction(async (tx) => {
|
|
321
|
+
// Repositories automatically use the transaction 'tx'
|
|
322
|
+
// because they are accessed within the scope of 'this.transaction'
|
|
323
|
+
// and injected via injectRepository which handles context propagation.
|
|
324
|
+
|
|
325
|
+
// Alternatively, explicitly bind:
|
|
326
|
+
// const txRepo = this.#orderRepository.withTransaction(tx);
|
|
327
|
+
|
|
328
|
+
const order = await this.#orderRepository.insert({ ... });
|
|
329
|
+
await this.#itemRepository.insertMany(data.items.map(i => ({ ...i, orderId: order.id })));
|
|
330
|
+
|
|
331
|
+
// If an error is thrown here, everything is rolled back.
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Soft Deletes
|
|
338
|
+
|
|
339
|
+
When using the `Entity` base class, the `delete` and `deleteByQuery` methods perform a soft delete by setting the `deleteTimestamp`. The `load` and `loadByQuery` methods automatically filter out soft-deleted records.
|
|
340
|
+
|
|
341
|
+
To permanently remove records, use `hardDelete` or `hardDeleteByQuery`.
|
|
342
|
+
|
|
343
|
+
### SQL Helper Functions
|
|
344
|
+
|
|
345
|
+
The module exports SQL helpers in `@tstdl/base/orm/sqls` for complex queries.
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
import { sql } from 'drizzle-orm';
|
|
349
|
+
import { interval, TRANSACTION_TIMESTAMP } from '@tstdl/base/orm/sqls';
|
|
350
|
+
|
|
351
|
+
// Find records created in the last 7 days
|
|
352
|
+
const recent = await repository.loadManyByQuery({
|
|
353
|
+
createTimestamp: { $gt: sql`${TRANSACTION_TIMESTAMP} - ${interval(7, 'days')}` },
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## 📚 API
|
|
358
|
+
|
|
359
|
+
### Decorators
|
|
360
|
+
|
|
361
|
+
| Decorator | Target | Description |
|
|
362
|
+
| :----------------------------------- | :--------- | :------------------------------------------------------ |
|
|
363
|
+
| `@Table({ name?, schema? })` | Class | Configures table name and schema. |
|
|
364
|
+
| `@Unique(columns?, options?)` | Class/Prop | Defines unique constraints. |
|
|
365
|
+
| `@Index(columns?, options?)` | Class/Prop | Defines database indexes. |
|
|
366
|
+
| `@Check(name, builder)` | Class | Defines a SQL CHECK constraint. |
|
|
367
|
+
| `@ForeignKey(...)` | Class | Defines a foreign key constraint. |
|
|
368
|
+
| `@ParadeIndex(options)` | Class/Prop | Configures a ParadeDB BM25 index. |
|
|
369
|
+
| `@TimeToLive(ttl, mode)` | Class | Sets TTL for automatic deletion based on creation time. |
|
|
370
|
+
| `@PrimaryKeyProperty()` | Prop | Marks the primary key column. |
|
|
371
|
+
| `@References(target)` | Prop | Defines a foreign key relationship. |
|
|
372
|
+
| `@EncryptedProperty()` | Prop | Marks column for encryption (`bytea`). |
|
|
373
|
+
| `@EmbeddedProperty(type)` | Prop | Embeds another class's properties. |
|
|
374
|
+
| `@GeneratedTsVector(opts)` | Prop | Creates a generated `tsvector` column. |
|
|
375
|
+
| `@TrigramIndex(opts)` | Prop | Creates a GIN/GIST trigram index. |
|
|
376
|
+
| `@Expires(opts)` | Prop | Sets expiration based on the property value. |
|
|
377
|
+
| `@UuidProperty()` | Prop | Maps to `uuid` column. |
|
|
378
|
+
| `@TimestampProperty()` | Prop | Maps to `timestamp with time zone` (number). |
|
|
379
|
+
| `@NumericDateProperty()` | Prop | Maps to `date` (number YYYYMMDD). |
|
|
380
|
+
| `@JsonProperty()` | Prop | Maps to `jsonb` column. |
|
|
381
|
+
| `@NumericProperty(precision, scale)` | Prop | Maps to `numeric` column. |
|
|
382
|
+
| `@TsVectorProperty()` | Prop | Maps to `tsvector` column. |
|
|
383
|
+
|
|
384
|
+
### Repository Methods
|
|
385
|
+
|
|
386
|
+
| Method | Description |
|
|
387
|
+
| :---------------------------------- | :------------------------------------------------------- |
|
|
388
|
+
| `load(id)` | Loads an entity by ID. Throws if not found. |
|
|
389
|
+
| `tryLoad(id)` | Loads an entity by ID. Returns `undefined` if not found. |
|
|
390
|
+
| `loadByQuery(query)` | Loads first match. Throws if not found. |
|
|
391
|
+
| `tryLoadByQuery(query)` | Loads first match. Returns `undefined` if not found. |
|
|
392
|
+
| `loadMany(ids)` | Loads multiple entities by ID. |
|
|
393
|
+
| `loadManyByQuery(query)` | Loads all matches. |
|
|
394
|
+
| `loadAll()` | Loads all entities in the table. |
|
|
395
|
+
| `insert(entity)` | Inserts a new entity. |
|
|
396
|
+
| `insertMany(entities)` | Inserts multiple entities. |
|
|
397
|
+
| `insertIfNotExists(target, entity)` | Inserts if no conflict on target columns. |
|
|
398
|
+
| `update(id, update)` | Updates an entity by ID. |
|
|
399
|
+
| `updateByQuery(query, update)` | Updates entities matching query. |
|
|
400
|
+
| `upsert(target, entity)` | Inserts or updates on conflict. |
|
|
401
|
+
| `delete(id)` | Soft deletes (if supported) or hard deletes by ID. |
|
|
402
|
+
| `deleteByQuery(query)` | Soft deletes matching entity. |
|
|
403
|
+
| `hardDelete(id)` | Permanently removes the record. |
|
|
404
|
+
| `search(options)` | Performs full-text search (TsVector, Trigram, Parade). |
|
|
405
|
+
| `count()` | Returns total count of entities. |
|
|
406
|
+
| `countByQuery(query)` | Returns the count of matching records. |
|
|
407
|
+
| `has(id)` | Checks if an ID exists. |
|
|
408
|
+
| `transaction(handler)` | Executes handler in a transaction. |
|
|
409
|
+
|
|
410
|
+
### Query Operators
|
|
411
|
+
|
|
412
|
+
| Operator | Description |
|
|
413
|
+
| :---------------------- | :----------------------------------- |
|
|
414
|
+
| `$eq` / `$neq` | Equal / Not Equal |
|
|
415
|
+
| `$gt` / `$gte` | Greater Than / Greater Than or Equal |
|
|
416
|
+
| `$lt` / `$lte` | Less Than / Less Than or Equal |
|
|
417
|
+
| `$in` / `$nin` | In Array / Not In Array |
|
|
418
|
+
| `$regex` | Regular Expression match |
|
|
419
|
+
| `$and` / `$or` / `$nor` | Logical operators |
|
|
420
|
+
| `$not` | Negation |
|
|
421
|
+
| `$tsvector` | PostgreSQL Text Search |
|
|
422
|
+
| `$trigram` | Trigram Similarity Search |
|
|
423
|
+
| `$parade` | ParadeDB Search |
|
package/orm/decorators.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Defines decorators for ORM entities and columns, used to configure database schema mapping.
|
|
4
4
|
*/
|
|
5
5
|
import type { SQL } from 'drizzle-orm';
|
|
6
|
-
import type { ExtraConfigColumn } from 'drizzle-orm/pg-core';
|
|
6
|
+
import type { ExtraConfigColumn, UpdateDeleteAction } from 'drizzle-orm/pg-core';
|
|
7
7
|
import type { LiteralUnion, SetRequired } from 'type-fest';
|
|
8
8
|
import { type SpecificCreateDecoratorOptions } from '../reflection/index.js';
|
|
9
9
|
import type { AbstractConstructor, Record, TypedOmit } from '../types/index.js';
|
|
@@ -87,6 +87,8 @@ type ReferenceReflectionData<T extends AnyEntity = AnyEntity> = {
|
|
|
87
87
|
target: () => EntityType<T>;
|
|
88
88
|
targetColumn?: TargetColumnPath<T>;
|
|
89
89
|
excludeTenant?: boolean;
|
|
90
|
+
onDelete?: UpdateDeleteAction;
|
|
91
|
+
onUpdate?: UpdateDeleteAction;
|
|
90
92
|
};
|
|
91
93
|
/**
|
|
92
94
|
* Reflection data for unique constraints.
|
|
@@ -122,6 +124,8 @@ export type ForeignKeyReflectionData = {
|
|
|
122
124
|
options?: {
|
|
123
125
|
name?: string;
|
|
124
126
|
naming?: NamingStrategy;
|
|
127
|
+
onDelete?: UpdateDeleteAction;
|
|
128
|
+
onUpdate?: UpdateDeleteAction;
|
|
125
129
|
};
|
|
126
130
|
};
|
|
127
131
|
export type IndexOptions<T extends BaseEntity> = {
|
package/orm/decorators.js
CHANGED
|
@@ -71,7 +71,7 @@ export function PrimaryKeyProperty() {
|
|
|
71
71
|
export function Reference(target, targetColumnOrOptions) {
|
|
72
72
|
const targetColumn = (isString(targetColumnOrOptions) ? targetColumnOrOptions : targetColumnOrOptions?.targetColumn);
|
|
73
73
|
const options = isString(targetColumnOrOptions) ? undefined : targetColumnOrOptions;
|
|
74
|
-
return createColumnDecorator({ references: [{ target, targetColumn, excludeTenant: options?.excludeTenant }] });
|
|
74
|
+
return createColumnDecorator({ references: [{ target, targetColumn, excludeTenant: options?.excludeTenant, onDelete: options?.onDelete, onUpdate: options?.onUpdate }] });
|
|
75
75
|
}
|
|
76
76
|
export {
|
|
77
77
|
/** @deprecated use {@link Reference} instead. */
|
|
@@ -15,13 +15,13 @@ import { typeExtends } from '../../../utils/index.js';
|
|
|
15
15
|
import { merge } from '../../../utils/merge.js';
|
|
16
16
|
import { compileDereferencer } from '../../../utils/object/dereference.js';
|
|
17
17
|
import { fromEntries, mapObjectKeysToSnakeCase, objectEntries } from '../../../utils/object/object.js';
|
|
18
|
-
import { assertDefined,
|
|
18
|
+
import { assertDefined, isArray, isDefined, isNotNull, isNull, isString, isUndefined } from '../../../utils/type-guards.js';
|
|
19
19
|
import { resolveValueOrProvider } from '../../../utils/value-or-provider.js';
|
|
20
20
|
import { bytea, numericDate, timestamp, tsvector } from '../../data-types/index.js';
|
|
21
21
|
import { TenantBaseEntity, TenantEntity } from '../../entity.js';
|
|
22
22
|
import { getEnumName } from '../../enums.js';
|
|
23
23
|
import { JsonSchema, NumericDateSchema, NumericSchema, TimestampSchema, TsVectorSchema, UuidSchema } from '../../schemas/index.js';
|
|
24
|
-
import { getInheritanceMetadata, isChildEntity } from '../../utils.js';
|
|
24
|
+
import { getEntitySchema, getEntityTableName, getInheritanceMetadata, getTableReflectionDatas, isChildEntity } from '../../utils.js';
|
|
25
25
|
import { decryptBytes, encryptBytes } from '../encryption.js';
|
|
26
26
|
import { convertQuery, resolveTargetColumn, resolveTargetColumns } from '../query-converter.js';
|
|
27
27
|
const getDbSchema = memoizeSingle(pgSchema);
|
|
@@ -42,8 +42,8 @@ export function getColumnDefinitionsMap(table) {
|
|
|
42
42
|
export function _getDrizzleTableFromType(type, fallbackSchemaName) {
|
|
43
43
|
const tableReflectionDatas = getTableReflectionDatas(type);
|
|
44
44
|
const mergedTableReflectionData = tableReflectionDatas.reduceRight((merged, data) => ({ ...merged, ...data }), {});
|
|
45
|
-
const schema =
|
|
46
|
-
const tableName =
|
|
45
|
+
const schema = getEntitySchema(type, fallbackSchemaName);
|
|
46
|
+
const tableName = getEntityTableName(type);
|
|
47
47
|
const dbSchema = getDbSchema(schema);
|
|
48
48
|
const inheritanceMetadata = getInheritanceMetadata(type);
|
|
49
49
|
const allColumnDefinitions = getPostgresColumnEntries(type, dbSchema, tableName, undefined, '', { filterInherited: false }, type);
|
|
@@ -130,7 +130,7 @@ export function _getDrizzleTableFromType(type, fallbackSchemaName) {
|
|
|
130
130
|
if (isDefined(inheritanceMetadata) && isDefined(childEntityMetadata)) {
|
|
131
131
|
const hasTenantId = isDefined(table['tenantId']);
|
|
132
132
|
constraints.push(check(getIdentifier(tableName, discriminatorColumn, 'check'), eq(table[discriminatorColumn], sql.raw(`'${childEntityMetadata.discriminatorValue}'`))), foreignKey({
|
|
133
|
-
name: getForeignKeyName(tableName,
|
|
133
|
+
name: getForeignKeyName(tableName, getEntityTableName(reflectionRegistry.getMetadata(type).parent), [...(hasTenantId ? ['tenantId'] : []), discriminatorColumn, 'id']),
|
|
134
134
|
columns: [
|
|
135
135
|
...(hasTenantId ? [table['tenantId']] : []),
|
|
136
136
|
table[discriminatorColumn],
|
|
@@ -247,7 +247,7 @@ export function _getDrizzleTableFromType(type, fallbackSchemaName) {
|
|
|
247
247
|
const foreignTable = getDrizzleTableFromType(tenantReferenceData.target(), dbSchema.schemaName);
|
|
248
248
|
const nonTenantColumn = tenantReferenceData.targetColumn ?? 'id';
|
|
249
249
|
return foreignKey({
|
|
250
|
-
name: getForeignKeyName(tableName,
|
|
250
|
+
name: getForeignKeyName(tableName, getEntityTableName(tenantReferenceData.target()), [nonTenantColumn]),
|
|
251
251
|
columns: [getColumn(table, 'tenantId'), getColumn(table, columnDefinition.name)],
|
|
252
252
|
foreignColumns: [getColumn(foreignTable, 'tenantId'), getColumn(foreignTable, nonTenantColumn)],
|
|
253
253
|
});
|
|
@@ -257,11 +257,18 @@ export function _getDrizzleTableFromType(type, fallbackSchemaName) {
|
|
|
257
257
|
return tableReflectionData.foreignKeys?.map((foreignKeyData) => {
|
|
258
258
|
const foreignKeyTarget = foreignKeyData.target();
|
|
259
259
|
const foreignTable = getDrizzleTableFromType(foreignKeyTarget, dbSchema.schemaName);
|
|
260
|
-
|
|
261
|
-
name: foreignKeyData.options?.name ?? getForeignKeyName(tableName,
|
|
260
|
+
let builder = foreignKey({
|
|
261
|
+
name: foreignKeyData.options?.name ?? getForeignKeyName(tableName, getEntityTableName(foreignKeyData.target()), foreignKeyData.columns, { naming: foreignKeyData.options?.naming }),
|
|
262
262
|
columns: foreignKeyData.columns.map((column) => getColumn(table, column)),
|
|
263
263
|
foreignColumns: foreignKeyData.foreignColumns.map((column) => getColumn(foreignTable, column)),
|
|
264
264
|
});
|
|
265
|
+
if (isDefined(foreignKeyData.options?.onDelete)) {
|
|
266
|
+
builder = builder.onDelete(foreignKeyData.options.onDelete);
|
|
267
|
+
}
|
|
268
|
+
if (isDefined(foreignKeyData.options?.onUpdate)) {
|
|
269
|
+
builder = builder.onUpdate(foreignKeyData.options.onUpdate);
|
|
270
|
+
}
|
|
271
|
+
return builder;
|
|
265
272
|
}) ?? [];
|
|
266
273
|
}),
|
|
267
274
|
...tableReflectionDatas.flatMap((tableReflectionData) => tableReflectionData.unique).filter(isDefined).map((data) => {
|
|
@@ -398,7 +405,7 @@ function getPostgresColumn(tableName, columnName, dbSchema, propertySchema, refl
|
|
|
398
405
|
if (((reflectionData.primaryKey == true) || (context.property == 'id' && reflectionData.primaryKey != false)) && (options.skipPrimaryKey != true)) {
|
|
399
406
|
column = column.primaryKey();
|
|
400
407
|
}
|
|
401
|
-
for (const { target, targetColumn, excludeTenant } of reflectionData.references ?? []) {
|
|
408
|
+
for (const { target, targetColumn, excludeTenant, onDelete, onUpdate } of reflectionData.references ?? []) {
|
|
402
409
|
column = column.references(() => {
|
|
403
410
|
const targetType = target();
|
|
404
411
|
if ((excludeTenant != true) && (typeExtends(context.type, TenantBaseEntity) || typeExtends(context.type, TenantEntity)) && (typeExtends(targetType, TenantBaseEntity) || typeExtends(targetType, TenantEntity))) {
|
|
@@ -406,7 +413,7 @@ function getPostgresColumn(tableName, columnName, dbSchema, propertySchema, refl
|
|
|
406
413
|
}
|
|
407
414
|
const targetTable = getDrizzleTableFromType(targetType, dbSchema.schemaName);
|
|
408
415
|
return targetTable[(targetColumn ?? 'id')];
|
|
409
|
-
});
|
|
416
|
+
}, { onDelete, onUpdate });
|
|
410
417
|
}
|
|
411
418
|
return column;
|
|
412
419
|
}
|
|
@@ -462,9 +469,6 @@ export function getPgEnum(schema, enumeration, context) {
|
|
|
462
469
|
}
|
|
463
470
|
return dbEnum;
|
|
464
471
|
}
|
|
465
|
-
function getDefaultTableName(type) {
|
|
466
|
-
return toSnakeCase(isString(type.entityName) ? type.entityName : type.name.replace(/\d+$/u, ''));
|
|
467
|
-
}
|
|
468
472
|
function getPrimaryKeyName(tableName, columnsOrBaseName, options) {
|
|
469
473
|
return getIdentifier(tableName, columnsOrBaseName, 'pk', options);
|
|
470
474
|
}
|
|
@@ -486,23 +490,6 @@ function getForeignKeyName(tableName, foreignTableName, columnsOrBaseName, optio
|
|
|
486
490
|
}
|
|
487
491
|
return identifier;
|
|
488
492
|
}
|
|
489
|
-
function getTableName(type) {
|
|
490
|
-
const tableReflectionDatas = getTableReflectionDatas(type);
|
|
491
|
-
const tableReflectionData = tableReflectionDatas[0];
|
|
492
|
-
return tableReflectionData?.name ?? getDefaultTableName(type);
|
|
493
|
-
}
|
|
494
|
-
function getTableReflectionDatas(type) {
|
|
495
|
-
const metadata = reflectionRegistry.getMetadata(type);
|
|
496
|
-
assertDefined(metadata, `Type ${type.name} does not have reflection metadata.`);
|
|
497
|
-
const tableReflectionDatas = [];
|
|
498
|
-
for (let currentMetadata = metadata; isNotNullOrUndefined(currentMetadata?.parent); currentMetadata = reflectionRegistry.getMetadata(currentMetadata.parent)) {
|
|
499
|
-
const tableReflectionData = currentMetadata.data.tryGet('orm');
|
|
500
|
-
if (isDefined(tableReflectionData)) {
|
|
501
|
-
tableReflectionDatas.push(tableReflectionData);
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
return tableReflectionDatas;
|
|
505
|
-
}
|
|
506
493
|
function getIdentifier(tableName, columnsOrBaseName, suffix, options) {
|
|
507
494
|
const middle = isString(columnsOrBaseName) ? columnsOrBaseName : getColumnNames(columnsOrBaseName).join('_');
|
|
508
495
|
const identifier = `${getTablePrefix(tableName, options?.naming)}_${middle}_${suffix}`;
|
|
@@ -12,7 +12,6 @@ export declare function encryptBytes(bytes: Uint8Array<ArrayBuffer>, key: Crypto
|
|
|
12
12
|
* @param bytes The byte array to decrypt (must include version and IV).
|
|
13
13
|
* @param key The CryptoKey to use for decryption.
|
|
14
14
|
* @returns A promise that resolves to the original decrypted byte array.
|
|
15
|
-
* @throws {DetailsError} If decryption fails (e.g., wrong key, corrupted data).
|
|
16
15
|
* @throws {Error} If the encryption version is invalid.
|
|
17
16
|
*/
|
|
18
17
|
export declare function decryptBytes(bytes: Uint8Array, key: CryptoKey): Promise<Uint8Array<ArrayBuffer>>;
|
package/orm/server/encryption.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Provides utility functions for encrypting and decrypting byte arrays using AES-GCM.
|
|
4
4
|
* It includes versioning to handle potential future changes in the encryption format.
|
|
5
5
|
*/
|
|
6
|
-
import { DetailsError } from '../../errors/index.js';
|
|
7
6
|
import { decrypt, encrypt } from '../../utils/cryptography.js';
|
|
8
7
|
import { getRandomBytes } from '../../utils/random.js';
|
|
9
8
|
import { assert } from '../../utils/type-guards.js';
|
|
@@ -36,7 +35,6 @@ export async function encryptBytes(bytes, key) {
|
|
|
36
35
|
* @param bytes The byte array to decrypt (must include version and IV).
|
|
37
36
|
* @param key The CryptoKey to use for decryption.
|
|
38
37
|
* @returns A promise that resolves to the original decrypted byte array.
|
|
39
|
-
* @throws {DetailsError} If decryption fails (e.g., wrong key, corrupted data).
|
|
40
38
|
* @throws {Error} If the encryption version is invalid.
|
|
41
39
|
*/
|
|
42
40
|
export async function decryptBytes(bytes, key) {
|
|
@@ -49,7 +47,6 @@ export async function decryptBytes(bytes, key) {
|
|
|
49
47
|
return new Uint8Array(decrypted);
|
|
50
48
|
}
|
|
51
49
|
catch (error) {
|
|
52
|
-
|
|
53
|
-
throw new DetailsError('Decrypt error', error);
|
|
50
|
+
throw new Error('Decryption failed.', { cause: error });
|
|
54
51
|
}
|
|
55
52
|
}
|
package/orm/server/index.d.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module
|
|
3
|
-
* Barrel file exporting core server-side ORM functionalities.
|
|
4
|
-
* Includes database connection, schema management, repositories, transactions,
|
|
5
|
-
* and query conversion utilities.
|
|
6
|
-
*/
|
|
7
1
|
export * from './database-schema.js';
|
|
8
2
|
export * from './database.js';
|
|
3
|
+
export * from './migration.js';
|
|
9
4
|
export * from './module.js';
|
|
10
5
|
export * from './query-converter.js';
|
|
11
6
|
export * from './repository-config.js';
|
package/orm/server/index.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module
|
|
3
|
-
* Barrel file exporting core server-side ORM functionalities.
|
|
4
|
-
* Includes database connection, schema management, repositories, transactions,
|
|
5
|
-
* and query conversion utilities.
|
|
6
|
-
*/
|
|
7
1
|
export * from './database-schema.js';
|
|
8
2
|
export * from './database.js';
|
|
3
|
+
export * from './migration.js';
|
|
9
4
|
export * from './module.js';
|
|
10
5
|
export * from './query-converter.js';
|
|
11
6
|
export * from './repository-config.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Injector, type ProvidersItem } from '../../injector/index.js';
|
|
2
|
+
export type DatabaseMigration = {
|
|
3
|
+
name: string;
|
|
4
|
+
migrate: () => void | Promise<void>;
|
|
5
|
+
dependencies?: string[];
|
|
6
|
+
};
|
|
7
|
+
export declare const DATABASE_MIGRATION: import("../../injector/index.js").InjectionToken<DatabaseMigration, never>;
|
|
8
|
+
/**
|
|
9
|
+
* Registers a database migration in the provided injector.
|
|
10
|
+
* @param name - The unique name of the migration.
|
|
11
|
+
* @param migrate - The migration function.
|
|
12
|
+
* @param options - Optional injector and dependencies.
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerDatabaseMigration(name: string, migrate: () => void | Promise<void>, { injector, dependencies }?: {
|
|
15
|
+
injector?: Injector;
|
|
16
|
+
dependencies?: string[];
|
|
17
|
+
}): void;
|
|
18
|
+
export declare function provideDatabaseMigrator(): ProvidersItem;
|
|
19
|
+
export declare function runDatabaseMigrations(): Promise<void>;
|