stabilize-orm 1.2.0 → 1.3.0
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/CHANGELOG.md +33 -5
- package/README.md +165 -129
- package/client.ts +7 -82
- package/hooks.ts +65 -22
- package/index.ts +7 -39
- package/migrations.ts +23 -38
- package/model.ts +115 -0
- package/package.json +3 -9
- package/repository.ts +56 -66
- package/decorators.ts +0 -170
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
- Further features and improvements coming soon.
|
|
8
|
+
|
|
9
|
+
## [1.3.0] - 2025-10-18
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- Introduced programmatic `defineModel` API for model definitions, eliminating the need for decorators (`model.ts`).
|
|
13
|
+
- Added `MetadataStorage` class to manage model configurations without `reflect-metadata`.
|
|
14
|
+
- Added support for defining lifecycle hooks in `ModelConfig` or as class methods (`hooks.ts`).
|
|
15
|
+
- Added `example.ts` to demonstrate the new programmatic API usage.
|
|
16
|
+
- Extended `ModelConfig` interface to support columns, relations, hooks, versioning, and soft deletes (`types.ts`).
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- Replaced decorator-based model definitions with `defineModel` API, removing dependency on `reflect-metadata` and TypeScript experimental features (`experimentalDecorators`, `emitDecoratorMetadata`).
|
|
20
|
+
- Updated `stabilize.ts` to export `defineModel` and remove `reflect-metadata` import.
|
|
21
|
+
- Modified `repository.ts` to use `MetadataStorage` for table names, columns, relations, validators, and soft delete fields.
|
|
22
|
+
- Rewrote `hooks.ts` to support hooks via `ModelConfig` and class methods, integrated with `MetadataStorage`.
|
|
23
|
+
- Updated `migrations.ts` to generate schemas using `MetadataStorage` instead of decorator metadata.
|
|
24
|
+
- Revised `types.ts` to remove decorator-related types and add `ModelConfig`, `ColumnConfig`, and `RelationConfig` interfaces.
|
|
25
|
+
- Updated `README.md` to reflect the new programmatic API, remove decorator references, and update examples.
|
|
26
|
+
- Ensured compatibility with `verbatimModuleSyntax` by using `export type` for type exports in `stabilize.ts`.
|
|
27
|
+
|
|
28
|
+
### Removed
|
|
29
|
+
- Deleted `decorators.ts` as decorators are no longer used.
|
|
30
|
+
- Removed dependency on `reflect-metadata` from the project.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- Fixed TypeScript type errors in `repository.ts` for `columns` and `relations` by mapping `MetadataStorage` outputs to match expected types.
|
|
34
|
+
- Corrected `runHooks` in `repository.ts` to call `hook.callback(entity)` instead of `hook()`.
|
|
35
|
+
- Fixed TypeScript `verbatimModuleSyntax` error in `stabilize.ts` by separating type and value exports.
|
|
36
|
+
|
|
5
37
|
## [1.1.2] - 2025-10-14
|
|
6
38
|
|
|
7
39
|
### Added
|
|
@@ -16,8 +48,4 @@ All notable changes to this project will be documented in this file.
|
|
|
16
48
|
- Enhanced documentation for open source best practices.
|
|
17
49
|
|
|
18
50
|
### Fixed
|
|
19
|
-
- Various bug fixes for connection handling and retry logic.
|
|
20
|
-
|
|
21
|
-
## [Unreleased]
|
|
22
|
-
|
|
23
|
-
- Further features and improvements coming soon.
|
|
51
|
+
- Various bug fixes for connection handling and retry logic.
|
package/README.md
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
# Stabilize ORM
|
|
2
2
|
|
|
3
|
-
_A Modern, Type-Safe, and Expressive ORM for
|
|
3
|
+
_A Modern, Type-Safe, and Expressive ORM for Bun_
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
**Stabilize** is a lightweight, feature-rich ORM designed for performance and developer experience. It provides a unified, database-agnostic API for **PostgreSQL**, **MySQL**, and **SQLite**. Powered by a robust query builder,
|
|
7
|
+
**Stabilize** is a lightweight, feature-rich ORM designed for performance and developer experience. It provides a unified, database-agnostic API for **PostgreSQL**, **MySQL**, and **SQLite**. Powered by a robust query builder, programmatic model definitions, automatic versioning, and a full-featured command-line interface, Stabilize is built to scale with your app.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
## 🚀 Features
|
|
12
12
|
|
|
13
13
|
- **Unified API**: Write once, run on PostgreSQL, MySQL, or SQLite.
|
|
14
|
-
- **
|
|
15
|
-
- **Full-Featured CLI**: Generate models, manage migrations, seed data, and reset your database from the command line.
|
|
14
|
+
- **Programmatic Model Definitions**: Define models and columns using the `defineModel` API with the `DataTypes` enum for database-agnostic schemas.
|
|
15
|
+
- **Full-Featured CLI**: Generate models, manage migrations, seed data, and reset your database from the command line with [stabilize-cli](https://github.com/ElectronSz/stabilize-cli).
|
|
16
16
|
- **Automatic Migrations**: Generate database-specific SQL schemas directly from your model definitions.
|
|
17
|
-
- **Versioned Models & Time-Travel**:
|
|
17
|
+
- **Versioned Models & Time-Travel**: Enable versioning in your model configuration for automatic history tables and snapshot queries.
|
|
18
18
|
- **Retry Logic**: Automatic exponential backoff for database queries to handle transient connection issues.
|
|
19
19
|
- **Connection Pooling**: Efficient connection management for PostgreSQL and MySQL.
|
|
20
20
|
- **Transactional Integrity**: Built-in support for atomic transactions with automatic rollback on failure.
|
|
21
21
|
- **Advanced Query Builder**: Fluent, chainable API for building complex queries, including joins, filters, ordering, and pagination.
|
|
22
|
-
- **Model Relationships**:
|
|
23
|
-
- **Soft Deletes**:
|
|
24
|
-
- **Lifecycle Hooks**:
|
|
22
|
+
- **Model Relationships**: Define `OneToOne`, `ManyToOne`, `OneToMany`, and `ManyToMany` relationships in the model configuration.
|
|
23
|
+
- **Soft Deletes**: Enable soft deletes in the model configuration for transparent "deleted" flags and safe row removal.
|
|
24
|
+
- **Lifecycle Hooks**: Define hooks in the model configuration or as class methods for lifecycle events like `beforeCreate`, `afterUpdate`, etc.
|
|
25
25
|
- **Pluggable Logging**: Includes a robust `ConsoleLogger` with support for file-based, rotating logs.
|
|
26
26
|
- **Custom Errors**: `StabilizeError` provides clear, consistent error handling.
|
|
27
27
|
- **Caching Layer**: Optional Redis-backed caching with `cache-aside` and `write-through` strategies.
|
|
@@ -30,14 +30,14 @@ _A Modern, Type-Safe, and Expressive ORM for Bun, Node.js, and Deno_
|
|
|
30
30
|
|
|
31
31
|
## 📦 Installation
|
|
32
32
|
|
|
33
|
-
Stabilize ORM requires a modern JavaScript runtime (Bun v1.
|
|
33
|
+
Stabilize ORM requires a modern JavaScript runtime (Bun v1.3+).
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
36
|
# Using Bun
|
|
37
|
-
bun add stabilize-orm
|
|
37
|
+
bun add stabilize-orm
|
|
38
38
|
|
|
39
39
|
# Using npm
|
|
40
|
-
npm install stabilize-orm
|
|
40
|
+
npm install stabilize-orm
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
---
|
|
@@ -56,14 +56,14 @@ npm install stabilize-orm reflect-metadata
|
|
|
56
56
|
|
|
57
57
|
## ⚙️ Configuration
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
Create a database configuration file.
|
|
60
60
|
|
|
61
61
|
```typescript
|
|
62
62
|
// config/database.ts
|
|
63
63
|
import { DBType, type DBConfig } from "stabilize-orm";
|
|
64
64
|
|
|
65
65
|
const dbConfig: DBConfig = {
|
|
66
|
-
type: DBType.Postgres,
|
|
66
|
+
type: DBType.Postgres,
|
|
67
67
|
connectionString: process.env.DATABASE_URL || "postgres://user:password@localhost:5432/mydb",
|
|
68
68
|
retryAttempts: 3,
|
|
69
69
|
retryDelay: 1000,
|
|
@@ -72,11 +72,10 @@ const dbConfig: DBConfig = {
|
|
|
72
72
|
export default dbConfig;
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
Next, create a central ORM instance
|
|
75
|
+
Next, create a central ORM instance for your application.
|
|
76
76
|
|
|
77
77
|
```typescript
|
|
78
78
|
// db.ts
|
|
79
|
-
import 'reflect-metadata';
|
|
80
79
|
import { Stabilize, type CacheConfig, type LoggerConfig, LogLevel } from "stabilize-orm";
|
|
81
80
|
import dbConfig from "./database";
|
|
82
81
|
|
|
@@ -88,7 +87,7 @@ const cacheConfig: CacheConfig = {
|
|
|
88
87
|
|
|
89
88
|
const loggerConfig: LoggerConfig = {
|
|
90
89
|
level: LogLevel.Info,
|
|
91
|
-
filePath:
|
|
90
|
+
filePath: "logs/stabilize.log",
|
|
92
91
|
maxFileSize: 5 * 1024 * 1024, // 5MB
|
|
93
92
|
maxFiles: 3,
|
|
94
93
|
};
|
|
@@ -100,80 +99,95 @@ export const orm = new Stabilize(dbConfig, cacheConfig, loggerConfig);
|
|
|
100
99
|
|
|
101
100
|
## 🏗️ Models & Relationships
|
|
102
101
|
|
|
103
|
-
Define your tables as classes using
|
|
102
|
+
Define your tables as classes using the `defineModel` function. The `DataTypes` enum ensures database-agnostic schemas.
|
|
104
103
|
|
|
105
104
|
### Example: Users and Roles (Many-to-Many) with Versioning
|
|
106
105
|
|
|
107
106
|
```typescript
|
|
108
107
|
// models/User.ts
|
|
109
|
-
import
|
|
110
|
-
import {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
108
|
+
import { defineModel, DataTypes, RelationType } from "stabilize-orm";
|
|
109
|
+
import { UserRole } from "./UserRole";
|
|
110
|
+
|
|
111
|
+
const User = defineModel({
|
|
112
|
+
tableName: "users",
|
|
113
|
+
versioned: true,
|
|
114
|
+
columns: {
|
|
115
|
+
id: { type: DataTypes.Integer, required: true },
|
|
116
|
+
email: { type: DataTypes.String, length: 100, required: true, unique: true },
|
|
117
|
+
},
|
|
118
|
+
relations: [
|
|
119
|
+
{
|
|
120
|
+
type: RelationType.OneToMany,
|
|
121
|
+
target: () => UserRole,
|
|
122
|
+
property: "roles",
|
|
123
|
+
foreignKey: "userId",
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
hooks: {
|
|
127
|
+
beforeCreate: (entity) => console.log(`Creating user: ${entity.email}`),
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Add a hook as a class method
|
|
132
|
+
User.prototype.afterCreate = async function () {
|
|
133
|
+
console.log(`Created user with ID: ${this.id}`);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export { User };
|
|
126
137
|
```
|
|
127
138
|
|
|
128
139
|
```typescript
|
|
129
140
|
// models/Role.ts
|
|
130
|
-
import
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
import { defineModel, DataTypes } from "stabilize-orm";
|
|
142
|
+
|
|
143
|
+
const Role = defineModel({
|
|
144
|
+
tableName: "roles",
|
|
145
|
+
columns: {
|
|
146
|
+
id: { type: DataTypes.Integer, required: true },
|
|
147
|
+
name: { type: DataTypes.String, length: 50, required: true, unique: true },
|
|
148
|
+
},
|
|
149
|
+
});
|
|
137
150
|
|
|
138
|
-
|
|
139
|
-
@Required() @Unique()
|
|
140
|
-
name!: string;
|
|
141
|
-
}
|
|
151
|
+
export { Role };
|
|
142
152
|
```
|
|
143
153
|
|
|
144
154
|
```typescript
|
|
145
155
|
// models/UserRole.ts
|
|
146
|
-
import
|
|
147
|
-
import {
|
|
148
|
-
import {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
156
|
+
import { defineModel, DataTypes, RelationType } from "stabilize-orm";
|
|
157
|
+
import { User } from "./User";
|
|
158
|
+
import { Role } from "./Role";
|
|
159
|
+
|
|
160
|
+
const UserRole = defineModel({
|
|
161
|
+
tableName: "user_roles",
|
|
162
|
+
columns: {
|
|
163
|
+
id: { type: DataTypes.Integer, required: true },
|
|
164
|
+
userId: { type: DataTypes.Integer, required: true, index: "idx_user_id" },
|
|
165
|
+
roleId: { type: DataTypes.Integer, required: true, index: "idx_role_id" },
|
|
166
|
+
},
|
|
167
|
+
relations: [
|
|
168
|
+
{
|
|
169
|
+
type: RelationType.ManyToOne,
|
|
170
|
+
target: () => User,
|
|
171
|
+
property: "user",
|
|
172
|
+
foreignKey: "userId",
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
type: RelationType.ManyToOne,
|
|
176
|
+
target: () => Role,
|
|
177
|
+
property: "role",
|
|
178
|
+
foreignKey: "roleId",
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
});
|
|
166
182
|
|
|
167
|
-
|
|
168
|
-
role?: Role;
|
|
169
|
-
}
|
|
183
|
+
export { UserRole };
|
|
170
184
|
```
|
|
171
185
|
|
|
172
186
|
---
|
|
173
187
|
|
|
174
188
|
## ⏳ Versioning & Auditing
|
|
175
189
|
|
|
176
|
-
Enable automatic history tracking and time-travel queries by
|
|
190
|
+
Enable automatic history tracking and time-travel queries by setting `versioned: true` in your model configuration.
|
|
177
191
|
|
|
178
192
|
- Each change is recorded in a `<table>_history` table with version, operation, and audit columns.
|
|
179
193
|
- Supports snapshot queries, rollbacks, audits, and time-travel.
|
|
@@ -181,15 +195,16 @@ Enable automatic history tracking and time-travel queries by adding `@Versioned(
|
|
|
181
195
|
### **Versioning Example**
|
|
182
196
|
|
|
183
197
|
```typescript
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
198
|
+
import { defineModel, DataTypes } from "stabilize-orm";
|
|
199
|
+
|
|
200
|
+
const User = defineModel({
|
|
201
|
+
tableName: "users",
|
|
202
|
+
versioned: true,
|
|
203
|
+
columns: {
|
|
204
|
+
id: { type: DataTypes.Integer, required: true },
|
|
205
|
+
name: { type: DataTypes.String, length: 100 },
|
|
206
|
+
},
|
|
207
|
+
});
|
|
193
208
|
|
|
194
209
|
// --- Using versioning features:
|
|
195
210
|
|
|
@@ -199,7 +214,7 @@ const userRepository = orm.getRepository(User);
|
|
|
199
214
|
await userRepository.rollback(1, 3); // roll back user with id=1 to version 3
|
|
200
215
|
|
|
201
216
|
// Get a snapshot as of a specific date
|
|
202
|
-
const userAsOf = await userRepository.asOf(1, new Date(
|
|
217
|
+
const userAsOf = await userRepository.asOf(1, new Date("2025-01-01T00:00:00Z"));
|
|
203
218
|
console.log(userAsOf);
|
|
204
219
|
|
|
205
220
|
// View full version history
|
|
@@ -211,95 +226,92 @@ console.log(history);
|
|
|
211
226
|
|
|
212
227
|
## 🔄 Model Lifecycle Hooks
|
|
213
228
|
|
|
214
|
-
Stabilize ORM supports lifecycle hooks
|
|
215
|
-
You can run logic before/after create, update, delete, or save.
|
|
229
|
+
Stabilize ORM supports lifecycle hooks defined in the model configuration or as class methods. You can run logic before/after create, update, delete, or save.
|
|
216
230
|
|
|
217
231
|
### **Hooks Example**
|
|
218
232
|
|
|
219
233
|
```typescript
|
|
220
|
-
import {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
234
|
+
import { defineModel, DataTypes } from "stabilize-orm";
|
|
235
|
+
|
|
236
|
+
const User = defineModel({
|
|
237
|
+
tableName: "users",
|
|
238
|
+
columns: {
|
|
239
|
+
id: { type: DataTypes.Integer, required: true },
|
|
240
|
+
name: { type: DataTypes.String, length: 100 },
|
|
241
|
+
createdAt: { type: DataTypes.DateTime },
|
|
242
|
+
updatedAt: { type: DataTypes.DateTime },
|
|
243
|
+
},
|
|
244
|
+
hooks: {
|
|
245
|
+
beforeCreate: (entity) => {
|
|
246
|
+
entity.createdAt = new Date();
|
|
247
|
+
},
|
|
248
|
+
beforeUpdate: (entity) => {
|
|
249
|
+
entity.updatedAt = new Date();
|
|
250
|
+
},
|
|
251
|
+
afterCreate: (entity) => {
|
|
252
|
+
console.log(`User created: ${entity.name}`);
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
});
|
|
240
256
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
257
|
+
// Add a hook as a class method
|
|
258
|
+
User.prototype.afterUpdate = async function () {
|
|
259
|
+
console.log(`Updated user: ${this.name}`);
|
|
260
|
+
};
|
|
245
261
|
|
|
246
|
-
|
|
247
|
-
logCreate() {
|
|
248
|
-
console.log(`User created: ${this.name}`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
262
|
+
export { User };
|
|
251
263
|
```
|
|
252
264
|
|
|
253
|
-
|
|
265
|
+
Supported hooks: `beforeCreate`, `afterCreate`, `beforeUpdate`, `afterUpdate`, `beforeDelete`, `afterDelete`, `beforeSave`, `afterSave`.
|
|
254
266
|
|
|
255
267
|
---
|
|
256
268
|
|
|
257
269
|
## 💻 Command-Line Interface (CLI)
|
|
258
270
|
|
|
259
|
-
Stabilize includes a powerful CLI for managing your workflow.
|
|
271
|
+
Stabilize includes a powerful CLI for managing your workflow. See: [stabilize-cli on GitHub](https://github.com/ElectronSz/stabilize-cli)
|
|
260
272
|
|
|
261
273
|
### Generating Files
|
|
262
274
|
|
|
263
275
|
- **Generate a model**:
|
|
264
276
|
```bash
|
|
265
|
-
|
|
277
|
+
stabilize-cli generate model Product
|
|
266
278
|
```
|
|
267
279
|
|
|
268
280
|
- **Generate a migration from a model**:
|
|
269
281
|
```bash
|
|
270
|
-
|
|
282
|
+
stabilize-cli generate migration User
|
|
271
283
|
```
|
|
272
284
|
|
|
273
285
|
- **Generate a seed file**:
|
|
274
286
|
```bash
|
|
275
|
-
|
|
287
|
+
stabilize-cli generate seed InitialRoles
|
|
276
288
|
```
|
|
277
289
|
|
|
278
290
|
### Database & Migration Management
|
|
279
291
|
|
|
280
292
|
- **Run all pending migrations**:
|
|
281
293
|
```bash
|
|
282
|
-
|
|
294
|
+
stabilize-cli migrate
|
|
283
295
|
```
|
|
284
296
|
|
|
285
297
|
- **Roll back the last migration**:
|
|
286
298
|
```bash
|
|
287
|
-
|
|
299
|
+
stabilize-cli migrate:rollback
|
|
288
300
|
```
|
|
289
301
|
|
|
290
302
|
- **Run all pending seeds (in dependency order)**:
|
|
291
303
|
```bash
|
|
292
|
-
|
|
304
|
+
stabilize-cli seed
|
|
293
305
|
```
|
|
294
306
|
|
|
295
307
|
- **Check the status of migrations and seeds**:
|
|
296
308
|
```bash
|
|
297
|
-
|
|
309
|
+
stabilize-cli status
|
|
298
310
|
```
|
|
299
311
|
|
|
300
312
|
- **Reset the database (drop, migrate, seed)**:
|
|
301
313
|
```bash
|
|
302
|
-
|
|
314
|
+
stabilize-cli db:reset
|
|
303
315
|
```
|
|
304
316
|
|
|
305
317
|
---
|
|
@@ -309,21 +321,22 @@ Stabilize includes a powerful CLI for managing your workflow.
|
|
|
309
321
|
### Basic CRUD with Repositories
|
|
310
322
|
|
|
311
323
|
```typescript
|
|
312
|
-
import { orm } from
|
|
313
|
-
import { User } from
|
|
324
|
+
import { orm } from "./db";
|
|
325
|
+
import { User } from "./models/User";
|
|
314
326
|
|
|
315
327
|
const userRepository = orm.getRepository(User);
|
|
316
328
|
|
|
317
|
-
const newUser = await userRepository.create({ email:
|
|
329
|
+
const newUser = await userRepository.create({ email: "lwazicd@icloud.com" });
|
|
318
330
|
const foundUser = await userRepository.findOne(newUser.id);
|
|
319
|
-
const updatedUser = await userRepository.update(newUser.id, { email:
|
|
331
|
+
const updatedUser = await userRepository.update(newUser.id, { email: "admin@offbytesecure.com" });
|
|
320
332
|
await userRepository.delete(newUser.id);
|
|
321
333
|
```
|
|
322
334
|
|
|
323
335
|
### Advanced Queries with the Query Builder
|
|
324
336
|
|
|
325
337
|
```typescript
|
|
326
|
-
const activeAdmins = await orm
|
|
338
|
+
const activeAdmins = await orm
|
|
339
|
+
.getRepository(UserRole)
|
|
327
340
|
.find()
|
|
328
341
|
.join("users", "user_roles.user_id = users.id")
|
|
329
342
|
.join("roles", "user_roles.role_id = roles.id")
|
|
@@ -354,9 +367,32 @@ console.log(activeAdmins);
|
|
|
354
367
|
|
|
355
368
|
## 🗑️ Soft Deletes
|
|
356
369
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
- Use `
|
|
370
|
+
Enable soft deletes by setting `softDelete: true` and marking a column (e.g., `deletedAt`) with `softDelete: true` in the model configuration.
|
|
371
|
+
|
|
372
|
+
- Use `repository.delete(id)` to mark an entity as deleted.
|
|
373
|
+
- Use `repository.recover(id)` to restore a soft-deleted entity.
|
|
374
|
+
- Queries automatically exclude soft-deleted rows unless specified otherwise.
|
|
375
|
+
|
|
376
|
+
### **Soft Delete Example**
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
import { defineModel, DataTypes } from "stabilize-orm";
|
|
380
|
+
|
|
381
|
+
const User = defineModel({
|
|
382
|
+
tableName: "users",
|
|
383
|
+
softDelete: true,
|
|
384
|
+
columns: {
|
|
385
|
+
id: { type: DataTypes.Integer, required: true },
|
|
386
|
+
email: { type: DataTypes.String, length: 100, required: true },
|
|
387
|
+
deletedAt: { type: DataTypes.DateTime, softDelete: true },
|
|
388
|
+
},
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
const userRepository = orm.getRepository(User);
|
|
392
|
+
await userRepository.create({ email: "lwazicd@icloud.com" });
|
|
393
|
+
await userRepository.delete(1); // Soft delete
|
|
394
|
+
await userRepository.recover(1); // Recover
|
|
395
|
+
```
|
|
360
396
|
|
|
361
397
|
---
|
|
362
398
|
|
|
@@ -416,6 +452,6 @@ Licensed under the MIT License. See [LICENSE.md](./LICENSE.md) for details.
|
|
|
416
452
|
|
|
417
453
|
Created with ❤️ by **ElectronSz**
|
|
418
454
|
<br/>
|
|
419
|
-
<em>File last updated: 2025-10-
|
|
455
|
+
<em>File last updated: 2025-10-18 22:10:00 SAST</em>
|
|
420
456
|
|
|
421
457
|
</div>
|