@rws-framework/db 3.8.0 → 3.9.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/LOADING_CONTEXT_FIX.md +139 -0
- package/LOADING_CONTEXT_IMPLEMENTATION.md +122 -0
- package/dist/models/core/RWSModel.d.ts +1 -1
- package/dist/models/core/RWSModel.js +29 -33
- package/dist/models/interfaces/IModel.d.ts +1 -1
- package/dist/models/utils/FindUtils.js +131 -70
- package/dist/models/utils/LoadingContext.d.ts +56 -0
- package/dist/models/utils/LoadingContext.js +119 -0
- package/dist/models/utils/LoadingContext.test.d.ts +5 -0
- package/dist/models/utils/LoadingContext.test.js +51 -0
- package/dist/models/utils/index.d.ts +7 -0
- package/dist/models/utils/index.js +17 -0
- package/package.json +1 -1
- package/src/models/core/RWSModel.ts +15 -13
- package/src/models/interfaces/IModel.ts +1 -1
- package/src/models/utils/FindUtils.ts +150 -84
- package/src/models/utils/LoadingContext.ts +140 -0
- package/src/models/utils/index.ts +7 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# LoadingContext Implementation - Solution 1 Documentation (Updated)
|
|
2
|
+
|
|
3
|
+
## Problem Statement
|
|
4
|
+
|
|
5
|
+
The RWS framework had two related issues in the postLoad mechanism:
|
|
6
|
+
|
|
7
|
+
### 1. Original Circular Reference Issue
|
|
8
|
+
- **User model postLoad** calls `userGroup.reload(true)`
|
|
9
|
+
- **UserGroup model postLoad** calls `User.find(owner, { cancelPostLoad: true })`
|
|
10
|
+
- If that User gets loaded elsewhere without `cancelPostLoad: true`, it could trigger an infinite cycle
|
|
11
|
+
|
|
12
|
+
### 2. Cross-Request Stack Persistence Issue (Discovered)
|
|
13
|
+
- The LoadingContext had a **global loading stack** that persisted across HTTP requests
|
|
14
|
+
- Stack built up and never got cleared between requests
|
|
15
|
+
- Caused false positive "already being loaded" errors for subsequent requests
|
|
16
|
+
- Led to models not loading properly and authentication failures
|
|
17
|
+
|
|
18
|
+
## Solution: Request-Scoped Loading Context
|
|
19
|
+
|
|
20
|
+
### Key Fix: Execution Context Isolation
|
|
21
|
+
|
|
22
|
+
The critical fix was changing from a **global static loading stack** to **per-execution-context stacks**:
|
|
23
|
+
|
|
24
|
+
**Before (Problematic):**
|
|
25
|
+
```typescript
|
|
26
|
+
class LoadingContext {
|
|
27
|
+
private static loadingStack: Set<string> = new Set(); // GLOBAL - persisted across requests
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**After (Fixed):**
|
|
32
|
+
```typescript
|
|
33
|
+
class LoadingContext {
|
|
34
|
+
private static executionContexts = new WeakMap<object, Set<string>>(); // Per-context isolation
|
|
35
|
+
|
|
36
|
+
static withNewExecutionContext<T>(fn: () => Promise<T>): Promise<T> {
|
|
37
|
+
// Creates fresh context for each operation
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Implementation Components
|
|
43
|
+
|
|
44
|
+
#### 1. LoadingContext Class (`/models/utils/LoadingContext.ts`) - Updated
|
|
45
|
+
|
|
46
|
+
**Key Changes:**
|
|
47
|
+
- **Execution Context Isolation**: Each operation gets its own loading stack
|
|
48
|
+
- **WeakMap for Context Storage**: Associates loading stacks with execution contexts
|
|
49
|
+
- **Automatic Context Creation**: `withNewExecutionContext()` creates fresh contexts
|
|
50
|
+
- **Per-Request Isolation**: Each HTTP request gets its own clean loading context
|
|
51
|
+
|
|
52
|
+
#### 2. FindUtils Integration (`/models/utils/LoadingUtils.ts`) - Critical Fix
|
|
53
|
+
|
|
54
|
+
**All top-level methods now wrap operations in new execution contexts:**
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
public static async findOneBy<T extends RWSModel<T>>(
|
|
58
|
+
opModel: OpModelType<T>,
|
|
59
|
+
findParams?: FindByType
|
|
60
|
+
): Promise<T | null> {
|
|
61
|
+
// CRITICAL: Wrap in new execution context to ensure clean loading stack
|
|
62
|
+
return LoadingContext.withNewExecutionContext(async () => {
|
|
63
|
+
// ... existing logic with circular reference protection
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### How The Fix Works
|
|
69
|
+
|
|
70
|
+
#### Before Fix (Problematic):
|
|
71
|
+
```
|
|
72
|
+
Request 1: User.find(11) -> adds "User:11" to global stack
|
|
73
|
+
Request 1: UserGroup.reload() -> adds "UserGroup:10" to global stack
|
|
74
|
+
Request 1: Completes, but stack NOT cleared
|
|
75
|
+
Request 2: User.find(11) -> "User:11" already in global stack -> FALSE POSITIVE error
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### After Fix (Working):
|
|
79
|
+
```
|
|
80
|
+
Request 1: LoadingContext.withNewExecutionContext() -> creates fresh context
|
|
81
|
+
Request 1: User.find(11) -> adds "User:11" to context-specific stack
|
|
82
|
+
Request 1: UserGroup.reload() -> adds "UserGroup:10" to same context stack
|
|
83
|
+
Request 1: Completes -> context automatically cleaned up
|
|
84
|
+
|
|
85
|
+
Request 2: LoadingContext.withNewExecutionContext() -> creates NEW fresh context
|
|
86
|
+
Request 2: User.find(11) -> adds "User:11" to NEW context stack -> works normally
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Request Isolation Benefits
|
|
90
|
+
|
|
91
|
+
1. **No Cross-Request Interference**: Each HTTP request gets its own loading context
|
|
92
|
+
2. **Automatic Cleanup**: No manual stack management needed
|
|
93
|
+
3. **Proper Circular Detection**: Still prevents infinite loops within single operations
|
|
94
|
+
4. **No False Positives**: Eliminates "already loading" errors between requests
|
|
95
|
+
|
|
96
|
+
### Configuration
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// Set maximum loading depth for new contexts (default: 10)
|
|
100
|
+
LoadingContext.setDefaultMaxDepth(15);
|
|
101
|
+
|
|
102
|
+
// Get current loading stack for debugging current context
|
|
103
|
+
console.log(LoadingContext.getLoadingStack());
|
|
104
|
+
|
|
105
|
+
// Manual context creation (usually not needed)
|
|
106
|
+
await LoadingContext.withNewExecutionContext(async () => {
|
|
107
|
+
// Database operations here get fresh context
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Testing Results
|
|
112
|
+
|
|
113
|
+
**Before Fix - Error Logs:**
|
|
114
|
+
```
|
|
115
|
+
Circular reference detected: User:11 is already being loaded. Breaking cycle.
|
|
116
|
+
UnauthorizedException: Unauthorized
|
|
117
|
+
Circular reference detected: User:11 is already being loaded. Breaking cycle.
|
|
118
|
+
Circular reference detected: UserGroup:10 is already being loaded. Breaking cycle.
|
|
119
|
+
Circular reference detected: UserGroup:10 is already being loaded. Breaking cycle.
|
|
120
|
+
// Repeated across multiple requests - FALSE POSITIVES
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**After Fix:**
|
|
124
|
+
- Clean loading per HTTP request
|
|
125
|
+
- No false positive circular reference detections
|
|
126
|
+
- Proper circular reference protection within individual operations
|
|
127
|
+
- No authentication failures due to loading issues
|
|
128
|
+
- No cross-request interference
|
|
129
|
+
|
|
130
|
+
### Backward Compatibility
|
|
131
|
+
|
|
132
|
+
- **100% backward compatible**: No changes needed to existing model code
|
|
133
|
+
- **Existing `cancelPostLoad` still works**: Provides additional layer of protection
|
|
134
|
+
- **All existing APIs preserved**: No breaking changes to any interfaces
|
|
135
|
+
- **Automatic context management**: Developers don't need to manage contexts manually
|
|
136
|
+
|
|
137
|
+
### Summary
|
|
138
|
+
|
|
139
|
+
This fix resolves both the original circular reference issue AND the newly discovered cross-request stack persistence problem. The key insight was that the loading context needs to be **request-scoped** rather than **application-global**. Each database operation chain now gets its own clean loading context, preventing both infinite recursion within operations and false positive detection across operations.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# LoadingContext Implementation - Solution 1 Documentation
|
|
2
|
+
|
|
3
|
+
## Problem Statement
|
|
4
|
+
|
|
5
|
+
The RWS framework had a potential infinite recursion issue in the postLoad mechanism where:
|
|
6
|
+
|
|
7
|
+
1. **User model postLoad** calls `userGroup.reload(true)`
|
|
8
|
+
2. **UserGroup model postLoad** calls `User.find(owner, { cancelPostLoad: true })`
|
|
9
|
+
3. If that User gets loaded elsewhere without `cancelPostLoad: true`, it could trigger an infinite cycle
|
|
10
|
+
|
|
11
|
+
The existing anti-recursion mechanism was **per-instance** rather than **per-loading-context**, meaning it only prevented the same object from running postLoad multiple times, but didn't prevent circular loading between different instances of related models.
|
|
12
|
+
|
|
13
|
+
## Solution: Context-Based Loading Stack
|
|
14
|
+
|
|
15
|
+
### Implementation Components
|
|
16
|
+
|
|
17
|
+
#### 1. LoadingContext Class (`/models/utils/LoadingContext.ts`)
|
|
18
|
+
|
|
19
|
+
A utility class that tracks the chain of models currently being loaded to prevent circular references:
|
|
20
|
+
|
|
21
|
+
**Key Features:**
|
|
22
|
+
- **Static loading stack**: Tracks `ModelType:ID` combinations currently being loaded
|
|
23
|
+
- **Circular reference detection**: Prevents loading a model that's already in the loading chain
|
|
24
|
+
- **Maximum depth protection**: Prevents infinite chains with configurable depth limit
|
|
25
|
+
- **Automatic cleanup**: Uses try/finally blocks to ensure proper cleanup
|
|
26
|
+
- **Debugging support**: Provides stack inspection and clear error messages
|
|
27
|
+
|
|
28
|
+
**Key Methods:**
|
|
29
|
+
- `isLoading(modelType, id)`: Check if a model is currently being loaded
|
|
30
|
+
- `startLoading(modelType, id)`: Mark a model as being loaded
|
|
31
|
+
- `finishLoading(modelType, id)`: Mark a model as finished loading
|
|
32
|
+
- `withLoadingContext(modelType, id, fn)`: Execute function with automatic context management
|
|
33
|
+
|
|
34
|
+
#### 2. FindUtils Integration (`/models/utils/FindUtils.ts`)
|
|
35
|
+
|
|
36
|
+
Modified all find methods to use LoadingContext:
|
|
37
|
+
|
|
38
|
+
**Changes in `find()`, `findOneBy()`, `findBy()`, and `paginate()`:**
|
|
39
|
+
- Check if model is already being loaded before creating instance
|
|
40
|
+
- Use `LoadingContext.withLoadingContext()` to wrap model loading
|
|
41
|
+
- Return `null` or skip items that are already being loaded
|
|
42
|
+
- Provide warning messages for detected circular references
|
|
43
|
+
|
|
44
|
+
#### 3. RWSModel Integration (`/models/core/RWSModel.ts`)
|
|
45
|
+
|
|
46
|
+
- Added LoadingContext import
|
|
47
|
+
- The reload method now uses FindUtils which automatically gets the protection
|
|
48
|
+
|
|
49
|
+
### How It Works
|
|
50
|
+
|
|
51
|
+
#### Normal Loading Flow
|
|
52
|
+
```
|
|
53
|
+
1. User.find(1) -> LoadingContext.startLoading('User', 1)
|
|
54
|
+
2. User._asyncFill() -> loads userGroup relation
|
|
55
|
+
3. UserGroup.reload() -> LoadingContext.startLoading('UserGroup', 2)
|
|
56
|
+
4. UserGroup._asyncFill() -> loads owner relation
|
|
57
|
+
5. User.find(owner) -> LoadingContext.startLoading('User', 3)
|
|
58
|
+
6. Complete normally -> LoadingContext.finishLoading() for each
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### Circular Reference Prevention
|
|
62
|
+
```
|
|
63
|
+
1. User.find(1) -> LoadingContext.startLoading('User', 1)
|
|
64
|
+
2. User._asyncFill() -> loads userGroup relation
|
|
65
|
+
3. UserGroup.reload() -> LoadingContext.startLoading('UserGroup', 2)
|
|
66
|
+
4. UserGroup._asyncFill() -> tries to load User.find(1) again
|
|
67
|
+
5. LoadingContext.isLoading('User', 1) returns true
|
|
68
|
+
6. Returns null instead of creating infinite loop
|
|
69
|
+
7. Warning logged: "Circular reference detected"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### Maximum Depth Protection
|
|
73
|
+
```
|
|
74
|
+
If loading chain exceeds configurable limit (default 10):
|
|
75
|
+
- Throws descriptive error with full loading stack
|
|
76
|
+
- Shows exact chain: "Model1:1 -> Model2:2 -> Model3:3 -> ..."
|
|
77
|
+
- Helps identify complex circular dependencies
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Benefits
|
|
81
|
+
|
|
82
|
+
1. **Complete Circular Reference Prevention**: Unlike the previous per-instance flag, this prevents all types of circular loading
|
|
83
|
+
2. **Transparent Integration**: Existing code doesn't need changes - works automatically through FindUtils
|
|
84
|
+
3. **Performance Optimized**: Minimal overhead - just Set operations for tracking
|
|
85
|
+
4. **Debugging Friendly**: Clear error messages and stack inspection capabilities
|
|
86
|
+
5. **Configurable**: Adjustable maximum depth and behavior
|
|
87
|
+
6. **Fail-Safe**: Always cleans up loading stack even if errors occur
|
|
88
|
+
|
|
89
|
+
### Configuration Options
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// Set maximum loading depth (default: 10)
|
|
93
|
+
LoadingContext.setMaxDepth(15);
|
|
94
|
+
|
|
95
|
+
// Get current loading stack for debugging
|
|
96
|
+
console.log(LoadingContext.getLoadingStack());
|
|
97
|
+
|
|
98
|
+
// Clear stack in emergency situations
|
|
99
|
+
LoadingContext.clearStack();
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Backward Compatibility
|
|
103
|
+
|
|
104
|
+
- **100% backward compatible**: No changes needed to existing model code
|
|
105
|
+
- **Existing `cancelPostLoad` still works**: Provides additional layer of protection
|
|
106
|
+
- **All existing APIs preserved**: No breaking changes to FindUtils or RWSModel
|
|
107
|
+
|
|
108
|
+
### Testing
|
|
109
|
+
|
|
110
|
+
A test file (`LoadingContext.test.ts`) demonstrates:
|
|
111
|
+
- Basic loading detection
|
|
112
|
+
- Circular reference prevention
|
|
113
|
+
- Maximum depth protection
|
|
114
|
+
- Automatic cleanup
|
|
115
|
+
|
|
116
|
+
### Error Handling
|
|
117
|
+
|
|
118
|
+
The implementation provides clear error messages:
|
|
119
|
+
- **Circular Reference**: "Circular reference detected: User:1 is already being loaded. Breaking cycle."
|
|
120
|
+
- **Maximum Depth**: "Maximum loading depth (10) exceeded. Possible circular reference detected. Loading stack: User:1 -> UserGroup:2 -> ..."
|
|
121
|
+
|
|
122
|
+
This solution provides robust protection against infinite recursion while maintaining full backward compatibility and excellent debugging capabilities.
|
|
@@ -12,11 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.RWSModel = void 0;
|
|
13
13
|
const decorators_1 = require("../../decorators");
|
|
14
14
|
const FieldsHelper_1 = require("../../helper/FieldsHelper");
|
|
15
|
-
const
|
|
16
|
-
const TimeSeriesUtils_1 = require("../utils/TimeSeriesUtils");
|
|
17
|
-
const ModelUtils_1 = require("../utils/ModelUtils");
|
|
18
|
-
const HydrateUtils_1 = require("../utils/HydrateUtils");
|
|
19
|
-
const FindUtils_1 = require("../utils/FindUtils");
|
|
15
|
+
const utils_1 = require("../utils");
|
|
20
16
|
class RWSModel {
|
|
21
17
|
static services = {};
|
|
22
18
|
id;
|
|
@@ -87,13 +83,13 @@ class RWSModel {
|
|
|
87
83
|
return this;
|
|
88
84
|
}
|
|
89
85
|
async hasRelation(key) {
|
|
90
|
-
return
|
|
86
|
+
return utils_1.RelationUtils.hasRelation(this.constructor, key);
|
|
91
87
|
}
|
|
92
88
|
async getRelationKey(key) {
|
|
93
|
-
return
|
|
89
|
+
return utils_1.RelationUtils.getRelationKey(this.constructor, key);
|
|
94
90
|
}
|
|
95
91
|
bindRelation(key, relatedModel) {
|
|
96
|
-
return
|
|
92
|
+
return utils_1.RelationUtils.bindRelation(relatedModel);
|
|
97
93
|
}
|
|
98
94
|
async _asyncFill(data, fullDataMode = false, allowRelations = true, postLoadExecute = true) {
|
|
99
95
|
const collections_to_models = {};
|
|
@@ -108,37 +104,36 @@ class RWSModel {
|
|
|
108
104
|
});
|
|
109
105
|
const seriesHydrationfields = [];
|
|
110
106
|
if (allowRelations) {
|
|
111
|
-
await
|
|
107
|
+
await utils_1.HydrateUtils.hydrateRelations(this, relManyData, relOneData, seriesHydrationfields, fullDataMode, data);
|
|
112
108
|
}
|
|
113
109
|
// Process regular fields and time series
|
|
114
|
-
await
|
|
110
|
+
await utils_1.HydrateUtils.hydrateDataFields(this, collections_to_models, relOneData, seriesHydrationfields, fullDataMode, data);
|
|
115
111
|
if (!this.isPostLoadExecuted() && postLoadExecute) {
|
|
116
112
|
await this.postLoad();
|
|
117
|
-
this.setPostLoadExecuted();
|
|
118
113
|
}
|
|
119
114
|
return this;
|
|
120
115
|
}
|
|
121
116
|
getModelScalarFields(model) {
|
|
122
|
-
return
|
|
117
|
+
return utils_1.ModelUtils.getModelScalarFields(model);
|
|
123
118
|
}
|
|
124
119
|
async getRelationOneMeta(classFields) {
|
|
125
|
-
return
|
|
120
|
+
return utils_1.RelationUtils.getRelationOneMeta(this, classFields);
|
|
126
121
|
}
|
|
127
122
|
static async getRelationOneMeta(model, classFields) {
|
|
128
|
-
return
|
|
123
|
+
return utils_1.RelationUtils.getRelationOneMeta(model, classFields);
|
|
129
124
|
}
|
|
130
125
|
async getRelationManyMeta(classFields) {
|
|
131
|
-
return
|
|
126
|
+
return utils_1.RelationUtils.getRelationManyMeta(this, classFields);
|
|
132
127
|
}
|
|
133
128
|
static async getRelationManyMeta(model, classFields) {
|
|
134
|
-
return
|
|
129
|
+
return utils_1.RelationUtils.getRelationManyMeta(model, classFields);
|
|
135
130
|
}
|
|
136
131
|
static async paginate(paginateParams, findParams) {
|
|
137
|
-
return await
|
|
132
|
+
return await utils_1.FindUtils.paginate(this, paginateParams, findParams);
|
|
138
133
|
}
|
|
139
134
|
async toMongo() {
|
|
140
135
|
const data = {};
|
|
141
|
-
const timeSeriesIds =
|
|
136
|
+
const timeSeriesIds = utils_1.TimeSeriesUtils.getTimeSeriesModelFields(this);
|
|
142
137
|
const timeSeriesHydrationFields = [];
|
|
143
138
|
for (const key in this) {
|
|
144
139
|
if (await this.hasRelation(key)) {
|
|
@@ -180,10 +175,10 @@ class RWSModel {
|
|
|
180
175
|
async save() {
|
|
181
176
|
const data = await this.toMongo();
|
|
182
177
|
let updatedModelData = data;
|
|
183
|
-
const entryExists = await
|
|
178
|
+
const entryExists = await utils_1.ModelUtils.entryExists(this);
|
|
184
179
|
if (entryExists) {
|
|
185
180
|
await this.preUpdate();
|
|
186
|
-
const pk =
|
|
181
|
+
const pk = utils_1.ModelUtils.findPrimaryKeyFields(this.constructor);
|
|
187
182
|
updatedModelData = await this.dbService.update(data, this.getCollection(), pk);
|
|
188
183
|
await this._asyncFill(updatedModelData);
|
|
189
184
|
await this.postUpdate();
|
|
@@ -198,12 +193,13 @@ class RWSModel {
|
|
|
198
193
|
return this;
|
|
199
194
|
}
|
|
200
195
|
static async getModelAnnotations(constructor) {
|
|
201
|
-
return
|
|
196
|
+
return utils_1.ModelUtils.getModelAnnotations(constructor);
|
|
202
197
|
}
|
|
203
198
|
async preUpdate() {
|
|
204
199
|
return;
|
|
205
200
|
}
|
|
206
201
|
async postLoad() {
|
|
202
|
+
this.setPostLoadExecuted();
|
|
207
203
|
return;
|
|
208
204
|
}
|
|
209
205
|
async postUpdate() {
|
|
@@ -216,19 +212,19 @@ class RWSModel {
|
|
|
216
212
|
return;
|
|
217
213
|
}
|
|
218
214
|
static isSubclass(constructor, baseClass) {
|
|
219
|
-
return
|
|
215
|
+
return utils_1.ModelUtils.isSubclass(constructor, baseClass);
|
|
220
216
|
}
|
|
221
217
|
hasTimeSeries() {
|
|
222
|
-
return
|
|
218
|
+
return utils_1.TimeSeriesUtils.checkTimeSeries(this.constructor);
|
|
223
219
|
}
|
|
224
220
|
static checkTimeSeries(constructor) {
|
|
225
|
-
return
|
|
221
|
+
return utils_1.TimeSeriesUtils.checkTimeSeries(constructor);
|
|
226
222
|
}
|
|
227
223
|
async isDbVariable(variable) {
|
|
228
|
-
return
|
|
224
|
+
return utils_1.ModelUtils.checkDbVariable(this.constructor, variable);
|
|
229
225
|
}
|
|
230
226
|
static async checkDbVariable(constructor, variable) {
|
|
231
|
-
return
|
|
227
|
+
return utils_1.ModelUtils.checkDbVariable(constructor, variable);
|
|
232
228
|
}
|
|
233
229
|
sanitizeDBData(data) {
|
|
234
230
|
const dataKeys = Object.keys(data);
|
|
@@ -246,13 +242,13 @@ class RWSModel {
|
|
|
246
242
|
return await this.services.dbService.watchCollection(collection, preRun);
|
|
247
243
|
}
|
|
248
244
|
static async findOneBy(findParams) {
|
|
249
|
-
return await
|
|
245
|
+
return await utils_1.FindUtils.findOneBy(this, findParams);
|
|
250
246
|
}
|
|
251
247
|
static async find(id, findParams = null) {
|
|
252
|
-
return await
|
|
248
|
+
return await utils_1.FindUtils.find(this, id, findParams);
|
|
253
249
|
}
|
|
254
250
|
static async findBy(findParams) {
|
|
255
|
-
return await
|
|
251
|
+
return await utils_1.FindUtils.findBy(this, findParams);
|
|
256
252
|
}
|
|
257
253
|
static async delete(conditions) {
|
|
258
254
|
const collection = Reflect.get(this, '_collection');
|
|
@@ -279,7 +275,7 @@ class RWSModel {
|
|
|
279
275
|
return RWSModel.loadModels();
|
|
280
276
|
}
|
|
281
277
|
checkRelDisabled(key) {
|
|
282
|
-
return
|
|
278
|
+
return utils_1.RelationUtils.checkRelDisabled(this, key);
|
|
283
279
|
}
|
|
284
280
|
static setServices(services) {
|
|
285
281
|
this.allModels = services.configService.get('db_models');
|
|
@@ -294,8 +290,8 @@ class RWSModel {
|
|
|
294
290
|
static getDb() {
|
|
295
291
|
return this.services.dbService;
|
|
296
292
|
}
|
|
297
|
-
async reload() {
|
|
298
|
-
const pk =
|
|
293
|
+
async reload(inPostLoad = false) {
|
|
294
|
+
const pk = utils_1.ModelUtils.findPrimaryKeyFields(this.constructor);
|
|
299
295
|
const where = {};
|
|
300
296
|
if (Array.isArray(pk)) {
|
|
301
297
|
for (const pkElem of pk) {
|
|
@@ -305,7 +301,7 @@ class RWSModel {
|
|
|
305
301
|
else {
|
|
306
302
|
where[pk] = this[pk];
|
|
307
303
|
}
|
|
308
|
-
return await
|
|
304
|
+
return await utils_1.FindUtils.findOneBy(this.constructor, { conditions: where, cancelPostLoad: inPostLoad });
|
|
309
305
|
}
|
|
310
306
|
}
|
|
311
307
|
exports.RWSModel = RWSModel;
|
|
@@ -9,7 +9,7 @@ export interface IModel {
|
|
|
9
9
|
save: () => Promise<this>;
|
|
10
10
|
getDb: () => DBService;
|
|
11
11
|
getCollection: () => string | null;
|
|
12
|
-
reload: () => Promise<RWSModel<any>>;
|
|
12
|
+
reload: (inPostLoad: boolean) => Promise<RWSModel<any>>;
|
|
13
13
|
delete: () => Promise<void>;
|
|
14
14
|
hasTimeSeries: () => boolean;
|
|
15
15
|
_asyncFill: (data: any, fullDataMode?: boolean, allowRelations?: boolean) => Promise<any>;
|