@iamkirbki/database-handler-core 2.0.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/dist/Database.js +130 -0
- package/dist/Query.js +186 -0
- package/dist/Record.js +172 -0
- package/dist/Schema.js +13 -0
- package/dist/Table.js +252 -0
- package/dist/abstract/Model.js +549 -0
- package/dist/abstract/User.js +6 -0
- package/dist/helpers/QueryStatementBuilder.js +409 -0
- package/dist/helpers/Validator.js +345 -0
- package/dist/index.js +49 -0
- package/dist/interfaces/IDatabaseAdapter.js +1 -0
- package/dist/interfaces/IStatementAdapter.js +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/query.js +1 -0
- package/dist/types/table.js +2 -0
- package/package.json +31 -0
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import Table from "@core/Table";
|
|
11
|
+
/**
|
|
12
|
+
* **Model** - Abstract base class for database models providing a fluent ORM-like interface.
|
|
13
|
+
*
|
|
14
|
+
* This abstract class serves as the foundation for all database models in the application,
|
|
15
|
+
* providing a complete CRUD (Create, Read, Update, Delete) interface with a chainable query
|
|
16
|
+
* builder pattern. It abstracts away the complexity of direct database operations while
|
|
17
|
+
* maintaining type safety through TypeScript generics.
|
|
18
|
+
*
|
|
19
|
+
* ### Key Features:
|
|
20
|
+
* - **Type-Safe Operations**: Fully typed CRUD operations using TypeScript generics
|
|
21
|
+
* - **Fluent Interface**: Chainable query methods for intuitive query building
|
|
22
|
+
* - **Automatic Table Mapping**: Table name derived from class name
|
|
23
|
+
* - **Zero Configuration**: Minimal setup required for basic operations
|
|
24
|
+
* - **Consistent API**: Uniform interface across all models
|
|
25
|
+
*
|
|
26
|
+
* ### Architecture:
|
|
27
|
+
* The Model class acts as a bridge between your application code and the underlying
|
|
28
|
+
* Table/Record infrastructure. It maintains internal state for query parameters and
|
|
29
|
+
* provides a clean, high-level API that feels natural for application developers.
|
|
30
|
+
*
|
|
31
|
+
* ### Type Parameter:
|
|
32
|
+
* @template T - The shape of your model data. Must extend `{ id: string }` to ensure
|
|
33
|
+
* all models have a primary key. This generic type flows through all
|
|
34
|
+
* operations, providing compile-time type checking.
|
|
35
|
+
*
|
|
36
|
+
* @example Basic Model Definition
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import Model from './abstract/Model';
|
|
39
|
+
*
|
|
40
|
+
* interface UserData {
|
|
41
|
+
* id: string;
|
|
42
|
+
* name: string;
|
|
43
|
+
* email: string;
|
|
44
|
+
* createdAt: string;
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* export default class User extends Model<UserData> {
|
|
48
|
+
* // Add custom methods here if needed
|
|
49
|
+
* public findByEmail(email: string): UserData | undefined {
|
|
50
|
+
* return this.where({ email }).get();
|
|
51
|
+
* }
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @example CRUD Operations
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const db = new Database('./app.db');
|
|
58
|
+
* const user = new User(db);
|
|
59
|
+
*
|
|
60
|
+
* // CREATE - Insert new record
|
|
61
|
+
* const newUser = user.create({
|
|
62
|
+
* id: '1',
|
|
63
|
+
* name: 'John Doe',
|
|
64
|
+
* email: 'john@example.com',
|
|
65
|
+
* createdAt: new Date().toISOString()
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* // READ - Fetch single record
|
|
69
|
+
* const foundUser = user.where({ id: '1' }).get();
|
|
70
|
+
* console.log(foundUser?.name); // "John Doe"
|
|
71
|
+
*
|
|
72
|
+
* // READ - Fetch all records
|
|
73
|
+
* const allUsers = user.all();
|
|
74
|
+
* console.log(allUsers.length); // Number of users
|
|
75
|
+
*
|
|
76
|
+
* // UPDATE - Modify existing record
|
|
77
|
+
* user.where({ id: '1' }).update({
|
|
78
|
+
* id: '1',
|
|
79
|
+
* name: 'John Updated',
|
|
80
|
+
* email: 'john@example.com',
|
|
81
|
+
* createdAt: new Date().toISOString()
|
|
82
|
+
* });
|
|
83
|
+
*
|
|
84
|
+
* // DELETE - Remove record
|
|
85
|
+
* user.where({ id: '1' }).delete();
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* @example Advanced Query Patterns
|
|
89
|
+
* ```typescript
|
|
90
|
+
* // Find user by email
|
|
91
|
+
* const user = userModel.where({ email: 'jane@example.com' }).get();
|
|
92
|
+
*
|
|
93
|
+
* // Update user by email
|
|
94
|
+
* userModel
|
|
95
|
+
* .where({ email: 'jane@example.com' })
|
|
96
|
+
* .update({ id: '2', name: 'Jane Smith', email: 'jane@example.com', createdAt: '...' });
|
|
97
|
+
*
|
|
98
|
+
* // Delete user by name
|
|
99
|
+
* userModel.where({ name: 'Bob Wilson' }).delete();
|
|
100
|
+
*
|
|
101
|
+
* // Check if user exists
|
|
102
|
+
* const exists = userModel.where({ id: '123' }).get() !== undefined;
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @example Custom Model Methods
|
|
106
|
+
* ```typescript
|
|
107
|
+
* export default class User extends Model<UserData> {
|
|
108
|
+
* // Find active users
|
|
109
|
+
* public findActive(): UserData[] {
|
|
110
|
+
* return this.all().filter(user => user.status === 'active');
|
|
111
|
+
* }
|
|
112
|
+
*
|
|
113
|
+
* // Soft delete by setting status
|
|
114
|
+
* public softDelete(id: string): void {
|
|
115
|
+
* const user = this.where({ id }).get();
|
|
116
|
+
* if (user) {
|
|
117
|
+
* this.where({ id }).update({ ...user, status: 'deleted' });
|
|
118
|
+
* }
|
|
119
|
+
* }
|
|
120
|
+
*
|
|
121
|
+
* // Count total users
|
|
122
|
+
* public count(): number {
|
|
123
|
+
* return this.all().length;
|
|
124
|
+
* }
|
|
125
|
+
* }
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* ### Best Practices:
|
|
129
|
+
* 1. **Always extend Model**: Never instantiate Model directly - it's abstract
|
|
130
|
+
* 2. **Define clear interfaces**: Create TypeScript interfaces for your data shapes
|
|
131
|
+
* 3. **Use where() before mutations**: Always call where() before update() or delete()
|
|
132
|
+
* 4. **Handle undefined**: get() can return undefined - check before using
|
|
133
|
+
* 5. **Keep models focused**: Add domain logic, but avoid bloated models
|
|
134
|
+
* 6. **Reset state**: Model maintains query state - create new instances for independent queries
|
|
135
|
+
*
|
|
136
|
+
* ### Limitations:
|
|
137
|
+
* - Query parameters persist between operations on the same instance
|
|
138
|
+
* - Complex queries (joins, aggregations) may require custom methods
|
|
139
|
+
* - Batch operations should be implemented in subclasses if needed
|
|
140
|
+
* - No built-in validation - implement in subclasses or use separate validators
|
|
141
|
+
*
|
|
142
|
+
* @abstract
|
|
143
|
+
* @since 1.0.0
|
|
144
|
+
* @see Table - Underlying table management class
|
|
145
|
+
* @see Record - Individual record manipulation class
|
|
146
|
+
*/
|
|
147
|
+
export default class Model {
|
|
148
|
+
/**
|
|
149
|
+
* Protected constructor - use static create() factory instead
|
|
150
|
+
*
|
|
151
|
+
* @param table - Table instance for database operations
|
|
152
|
+
*/
|
|
153
|
+
constructor(table) {
|
|
154
|
+
/**
|
|
155
|
+
* Current query parameters for filtering operations.
|
|
156
|
+
*
|
|
157
|
+
* This object stores the WHERE clause conditions set via the where() method.
|
|
158
|
+
* It persists across method calls on the same instance, allowing for chainable
|
|
159
|
+
* query building. Reset by calling where() with new parameters or creating
|
|
160
|
+
* a new model instance.
|
|
161
|
+
*
|
|
162
|
+
* @private
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* // Internal state after: user.where({ id: '1' })
|
|
166
|
+
* // QueryParams = { id: '1' }
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
this.QueryParams = {};
|
|
170
|
+
this.Table = table;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Create a new Model instance (async factory method).
|
|
174
|
+
*
|
|
175
|
+
* Creates a new model connected to the specified database. The table name is
|
|
176
|
+
* automatically derived from the class name (via this.constructor.name), so a
|
|
177
|
+
* class named `User` will interact with a table named `User`.
|
|
178
|
+
*
|
|
179
|
+
* **Important**: Ensure the table exists in the database before creating a model
|
|
180
|
+
* instance. The Model class does not create tables automatically.
|
|
181
|
+
*
|
|
182
|
+
* @param adapter - Database adapter instance to use for all operations
|
|
183
|
+
* @returns Promise resolving to the model instance
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* import { createDatabase } from '@handler/better-sqlite3';
|
|
188
|
+
* import User from './models/User';
|
|
189
|
+
*
|
|
190
|
+
* const db = createDatabase('./app.db');
|
|
191
|
+
* await db.exec(`CREATE TABLE IF NOT EXISTS User (
|
|
192
|
+
* id TEXT PRIMARY KEY,
|
|
193
|
+
* name TEXT NOT NULL,
|
|
194
|
+
* email TEXT UNIQUE
|
|
195
|
+
* )`);
|
|
196
|
+
*
|
|
197
|
+
* const userModel = await User.create(db);
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
static create(adapter) {
|
|
201
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
202
|
+
const table = yield Table.create(this.name, adapter);
|
|
203
|
+
return new this(table);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Get the Record instance for the current query parameters.
|
|
208
|
+
*
|
|
209
|
+
* This method provides access to the Record instance matching the current
|
|
210
|
+
* QueryParams. It's used internally by get(), update(), and delete() methods.
|
|
211
|
+
* Returns undefined if no matching record exists.
|
|
212
|
+
*
|
|
213
|
+
* @private
|
|
214
|
+
* @returns Promise resolving to the matching Record instance or undefined
|
|
215
|
+
*/
|
|
216
|
+
RecordGet() {
|
|
217
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
+
return yield this.Table.Record({ where: this.QueryParams });
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Retrieve a single record matching the current query parameters.
|
|
223
|
+
*
|
|
224
|
+
* Returns the data for the first record that matches the WHERE conditions set
|
|
225
|
+
* by where(). If no where() was called, behavior is undefined (typically returns
|
|
226
|
+
* the first record, but this is not guaranteed). Returns undefined if no matching
|
|
227
|
+
* record exists.
|
|
228
|
+
*
|
|
229
|
+
* **Best Practice**: Always call where() before get() to ensure predictable results.
|
|
230
|
+
*
|
|
231
|
+
* @returns Promise resolving to the matching record's data, or undefined if not found
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```typescript
|
|
235
|
+
* // Find user by ID
|
|
236
|
+
* const user = await userModel.where({ id: '123' }).get();
|
|
237
|
+
* if (user) {
|
|
238
|
+
* console.log(user.name);
|
|
239
|
+
* } else {
|
|
240
|
+
* console.log('User not found');
|
|
241
|
+
* }
|
|
242
|
+
*
|
|
243
|
+
* // Find user by email
|
|
244
|
+
* const user = await userModel.where({ email: 'john@example.com' }).get();
|
|
245
|
+
*
|
|
246
|
+
* // Check existence
|
|
247
|
+
* const exists = await userModel.where({ id: '456' }).get() !== undefined;
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
get() {
|
|
251
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
252
|
+
const record = yield this.RecordGet();
|
|
253
|
+
return record === null || record === void 0 ? void 0 : record.values;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Retrieve all records from the table.
|
|
258
|
+
*
|
|
259
|
+
* Returns an array containing the data for every record in the table. This method
|
|
260
|
+
* ignores any where() conditions - it always returns the complete table contents.
|
|
261
|
+
* The array will be empty if the table has no records.
|
|
262
|
+
*
|
|
263
|
+
* **Performance Note**: For large tables, consider implementing pagination or
|
|
264
|
+
* filtering in a custom method to avoid loading excessive data into memory.
|
|
265
|
+
*
|
|
266
|
+
* @returns Promise resolving to array of all records in the table
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* // Get all users
|
|
271
|
+
* const allUsers = await userModel.all();
|
|
272
|
+
* console.log(`Total users: ${allUsers.length}`);
|
|
273
|
+
*
|
|
274
|
+
* // Iterate over all records
|
|
275
|
+
* allUsers.forEach(user => {
|
|
276
|
+
* console.log(`${user.name} - ${user.email}`);
|
|
277
|
+
* });
|
|
278
|
+
*
|
|
279
|
+
* // Filter in memory
|
|
280
|
+
* const activeUsers = (await userModel.all()).filter(u => u.status === 'active');
|
|
281
|
+
*
|
|
282
|
+
* // Map to simpler structure
|
|
283
|
+
* const userNames = (await userModel.all()).map(u => u.name);
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
all() {
|
|
287
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
288
|
+
const records = yield this.Table.Records();
|
|
289
|
+
return records.map(record => record.values);
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Set WHERE clause conditions for subsequent operations.
|
|
294
|
+
*
|
|
295
|
+
* This method configures the query parameters that will be used by get(), update(),
|
|
296
|
+
* and delete() operations. It follows a fluent interface pattern, returning the
|
|
297
|
+
* model instance to allow method chaining.
|
|
298
|
+
*
|
|
299
|
+
* The parameters are stored internally and persist until where() is called again
|
|
300
|
+
* with different parameters or a new model instance is created.
|
|
301
|
+
*
|
|
302
|
+
* **Important**: Calling where() replaces any previous query parameters - it does
|
|
303
|
+
* not merge them. For AND conditions with multiple fields, pass all conditions in
|
|
304
|
+
* a single where() call.
|
|
305
|
+
*
|
|
306
|
+
* @param QueryParameters - Object mapping column names to their expected values.
|
|
307
|
+
* All conditions are combined with AND logic.
|
|
308
|
+
* @returns The model instance for method chaining
|
|
309
|
+
*
|
|
310
|
+
* @example Basic Usage
|
|
311
|
+
* ```typescript
|
|
312
|
+
* // Single condition
|
|
313
|
+
* const user = userModel.where({ id: '123' }).get();
|
|
314
|
+
*
|
|
315
|
+
* // Multiple conditions (AND logic)
|
|
316
|
+
* const user = userModel.where({
|
|
317
|
+
* email: 'john@example.com',
|
|
318
|
+
* status: 'active'
|
|
319
|
+
* }).get();
|
|
320
|
+
* ```
|
|
321
|
+
*
|
|
322
|
+
* @example Chaining Pattern
|
|
323
|
+
* ```typescript
|
|
324
|
+
* // Chain where() with other operations
|
|
325
|
+
* userModel
|
|
326
|
+
* .where({ id: '123' })
|
|
327
|
+
* .update({ id: '123', name: 'Updated Name', email: 'new@email.com' });
|
|
328
|
+
*
|
|
329
|
+
* userModel
|
|
330
|
+
* .where({ status: 'inactive' })
|
|
331
|
+
* .delete();
|
|
332
|
+
* ```
|
|
333
|
+
*
|
|
334
|
+
* @example State Persistence
|
|
335
|
+
* ```typescript
|
|
336
|
+
* // Query parameters persist
|
|
337
|
+
* const model = new User(db);
|
|
338
|
+
* model.where({ id: '123' });
|
|
339
|
+
* const user1 = model.get(); // Uses id: '123'
|
|
340
|
+
* const user2 = model.get(); // Still uses id: '123'
|
|
341
|
+
*
|
|
342
|
+
* // Reset with new where() call
|
|
343
|
+
* model.where({ id: '456' });
|
|
344
|
+
* const user3 = model.get(); // Now uses id: '456'
|
|
345
|
+
* ```
|
|
346
|
+
*/
|
|
347
|
+
where(QueryParameters) {
|
|
348
|
+
this.QueryParams = QueryParameters;
|
|
349
|
+
return this;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Insert a new record into the table.
|
|
353
|
+
*
|
|
354
|
+
* Creates a new database record with the provided data. The data object must
|
|
355
|
+
* include all required fields as defined by your table schema. Returns a Record
|
|
356
|
+
* instance wrapping the newly created data, or undefined if the insert fails.
|
|
357
|
+
*
|
|
358
|
+
* **Note**: This method does not use the where() query parameters - it always
|
|
359
|
+
* inserts a new record. Duplicate IDs or constraint violations will throw errors.
|
|
360
|
+
*
|
|
361
|
+
* @param data - Complete record data to insert. Must satisfy type T constraints.
|
|
362
|
+
* @returns Promise resolving to Record instance wrapping the created data, or undefined on failure
|
|
363
|
+
* @throws Database errors on constraint violations (duplicate IDs, etc.)
|
|
364
|
+
*
|
|
365
|
+
* @example Basic Insert
|
|
366
|
+
* ```typescript
|
|
367
|
+
* const newUser = await userModel.create({
|
|
368
|
+
* id: '123',
|
|
369
|
+
* name: 'John Doe',
|
|
370
|
+
* email: 'john@example.com',
|
|
371
|
+
* createdAt: new Date().toISOString()
|
|
372
|
+
* });
|
|
373
|
+
*
|
|
374
|
+
* if (newUser) {
|
|
375
|
+
* console.log('User created:', newUser.values);
|
|
376
|
+
* }
|
|
377
|
+
* ```
|
|
378
|
+
*
|
|
379
|
+
* @example Handling Duplicates
|
|
380
|
+
* ```typescript
|
|
381
|
+
* try {
|
|
382
|
+
* const user = await userModel.create({
|
|
383
|
+
* id: 'existing-id',
|
|
384
|
+
* name: 'Test',
|
|
385
|
+
* email: 'test@example.com'
|
|
386
|
+
* });
|
|
387
|
+
* } catch (error) {
|
|
388
|
+
* console.error('Failed to create user:', error.message);
|
|
389
|
+
* // Handle duplicate ID or constraint violation
|
|
390
|
+
* }
|
|
391
|
+
* ```
|
|
392
|
+
*
|
|
393
|
+
* @example Batch Insert
|
|
394
|
+
* ```typescript
|
|
395
|
+
* const usersData = [
|
|
396
|
+
* { id: '1', name: 'User 1', email: 'user1@example.com' },
|
|
397
|
+
* { id: '2', name: 'User 2', email: 'user2@example.com' },
|
|
398
|
+
* { id: '3', name: 'User 3', email: 'user3@example.com' }
|
|
399
|
+
* ];
|
|
400
|
+
*
|
|
401
|
+
* const createdUsers = await Promise.all(usersData.map(data => userModel.create(data)));
|
|
402
|
+
* console.log(`Created ${createdUsers.filter(u => u).length} users`);
|
|
403
|
+
* ```
|
|
404
|
+
*/
|
|
405
|
+
create(data) {
|
|
406
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
407
|
+
return yield this.Table.Insert(data);
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Update the record matching the current query parameters.
|
|
412
|
+
*
|
|
413
|
+
* Modifies the database record that matches the WHERE conditions set by where().
|
|
414
|
+
* The entire record is replaced with the new data - this is not a partial update.
|
|
415
|
+
* If no record matches the query parameters, this method does nothing silently.
|
|
416
|
+
*
|
|
417
|
+
* **Important**: Always call where() before update() to specify which record to modify.
|
|
418
|
+
* Without where(), the behavior is undefined and may update an arbitrary record.
|
|
419
|
+
*
|
|
420
|
+
* @param data - Complete replacement data for the record. Must satisfy type T.
|
|
421
|
+
* @returns void - No return value. Check with get() if you need confirmation.
|
|
422
|
+
*
|
|
423
|
+
* @example Basic Update
|
|
424
|
+
* ```typescript
|
|
425
|
+
* // Update user by ID
|
|
426
|
+
* userModel.where({ id: '123' }).update({
|
|
427
|
+
* id: '123',
|
|
428
|
+
* name: 'Updated Name',
|
|
429
|
+
* email: 'updated@example.com',
|
|
430
|
+
* createdAt: '2024-01-01T00:00:00Z'
|
|
431
|
+
* });
|
|
432
|
+
* ```
|
|
433
|
+
*
|
|
434
|
+
* @example Update with Verification
|
|
435
|
+
* ```typescript
|
|
436
|
+
* // Get current data
|
|
437
|
+
* const user = userModel.where({ id: '123' }).get();
|
|
438
|
+
*
|
|
439
|
+
* if (user) {
|
|
440
|
+
* // Modify specific field
|
|
441
|
+
* userModel.where({ id: '123' }).update({
|
|
442
|
+
* ...user,
|
|
443
|
+
* name: 'New Name'
|
|
444
|
+
* });
|
|
445
|
+
*
|
|
446
|
+
* // Verify update
|
|
447
|
+
* const updated = userModel.where({ id: '123' }).get();
|
|
448
|
+
* console.log('Updated successfully:', updated?.name === 'New Name');
|
|
449
|
+
* }
|
|
450
|
+
* ```
|
|
451
|
+
*
|
|
452
|
+
* @example Conditional Update
|
|
453
|
+
* ```typescript
|
|
454
|
+
* // Update by email instead of ID
|
|
455
|
+
* const user = userModel.where({ email: 'old@example.com' }).get();
|
|
456
|
+
*
|
|
457
|
+
* if (user) {
|
|
458
|
+
* userModel.where({ email: 'old@example.com' }).update({
|
|
459
|
+
* ...user,
|
|
460
|
+
* email: 'new@example.com'
|
|
461
|
+
* });
|
|
462
|
+
* }
|
|
463
|
+
* ```
|
|
464
|
+
*/
|
|
465
|
+
update(data) {
|
|
466
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
467
|
+
const record = yield this.RecordGet();
|
|
468
|
+
if (record) {
|
|
469
|
+
yield record.Update(data);
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Delete the record matching the current query parameters.
|
|
475
|
+
*
|
|
476
|
+
* Permanently removes the database record that matches the WHERE conditions set
|
|
477
|
+
* by where(). This operation cannot be undone. If no record matches the query
|
|
478
|
+
* parameters, this method does nothing silently.
|
|
479
|
+
*
|
|
480
|
+
* **Important**: Always call where() before delete() to specify which record to remove.
|
|
481
|
+
* Without where(), the behavior is undefined and may delete an arbitrary record.
|
|
482
|
+
*
|
|
483
|
+
* **Warning**: This is a permanent deletion. Consider implementing soft deletes
|
|
484
|
+
* (status flags) in your models if you need to recover deleted records.
|
|
485
|
+
*
|
|
486
|
+
* @returns Promise that resolves when deletion is complete
|
|
487
|
+
*
|
|
488
|
+
* @example Basic Deletion
|
|
489
|
+
* ```typescript
|
|
490
|
+
* // Delete user by ID
|
|
491
|
+
* await userModel.where({ id: '123' }).delete();
|
|
492
|
+
*
|
|
493
|
+
* // Verify deletion
|
|
494
|
+
* const deleted = await userModel.where({ id: '123' }).get();
|
|
495
|
+
* console.log('Deleted:', deleted === undefined); // true
|
|
496
|
+
* ```
|
|
497
|
+
*
|
|
498
|
+
* @example Safe Deletion with Confirmation
|
|
499
|
+
* ```typescript
|
|
500
|
+
* // Check before deleting
|
|
501
|
+
* const user = await userModel.where({ id: '123' }).get();
|
|
502
|
+
*
|
|
503
|
+
* if (user) {
|
|
504
|
+
* console.log(`Deleting user: ${user.name}`);
|
|
505
|
+
* await userModel.where({ id: '123' }).delete();
|
|
506
|
+
* console.log('User deleted successfully');
|
|
507
|
+
* } else {
|
|
508
|
+
* console.log('User not found');
|
|
509
|
+
* }
|
|
510
|
+
* ```
|
|
511
|
+
*
|
|
512
|
+
* @example Batch Deletion
|
|
513
|
+
* ```typescript
|
|
514
|
+
* // Delete all inactive users
|
|
515
|
+
* const inactiveUsers = (await userModel.all()).filter(u => u.status === 'inactive');
|
|
516
|
+
*
|
|
517
|
+
* for (const user of inactiveUsers) {
|
|
518
|
+
* await userModel.where({ id: user.id }).delete();
|
|
519
|
+
* }
|
|
520
|
+
*
|
|
521
|
+
* console.log(`Deleted ${inactiveUsers.length} inactive users`);
|
|
522
|
+
* ```
|
|
523
|
+
*
|
|
524
|
+
* @example Soft Delete Alternative
|
|
525
|
+
* ```typescript
|
|
526
|
+
* // Instead of permanent deletion, mark as deleted
|
|
527
|
+
* export default class User extends Model<UserData> {
|
|
528
|
+
* public async softDelete(id: string): Promise<void> {
|
|
529
|
+
* const user = await this.where({ id }).get();
|
|
530
|
+
* if (user) {
|
|
531
|
+
* await this.where({ id }).update({
|
|
532
|
+
* ...user,
|
|
533
|
+
* status: 'deleted',
|
|
534
|
+
* deletedAt: new Date().toISOString()
|
|
535
|
+
* });
|
|
536
|
+
* }
|
|
537
|
+
* }
|
|
538
|
+
* }
|
|
539
|
+
* ```
|
|
540
|
+
*/
|
|
541
|
+
delete() {
|
|
542
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
543
|
+
const record = yield this.RecordGet();
|
|
544
|
+
if (record) {
|
|
545
|
+
yield record.Delete();
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
}
|