@rws-framework/db 3.7.3 → 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 +38 -40
- 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 +24 -21
- 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,48 +104,49 @@ 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)) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
140
|
+
if (this[key] === null) {
|
|
141
|
+
// For null relations, use disconnect or set to null
|
|
142
|
+
data[key] = {
|
|
143
|
+
disconnect: true
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
data[key] = this.bindRelation(key, this[key]);
|
|
152
148
|
}
|
|
149
|
+
// Don't try to set the foreign key directly anymore
|
|
153
150
|
continue;
|
|
154
151
|
}
|
|
155
152
|
if (!(await this.isDbVariable(key))) {
|
|
@@ -178,10 +175,10 @@ class RWSModel {
|
|
|
178
175
|
async save() {
|
|
179
176
|
const data = await this.toMongo();
|
|
180
177
|
let updatedModelData = data;
|
|
181
|
-
const entryExists = await
|
|
178
|
+
const entryExists = await utils_1.ModelUtils.entryExists(this);
|
|
182
179
|
if (entryExists) {
|
|
183
180
|
await this.preUpdate();
|
|
184
|
-
const pk =
|
|
181
|
+
const pk = utils_1.ModelUtils.findPrimaryKeyFields(this.constructor);
|
|
185
182
|
updatedModelData = await this.dbService.update(data, this.getCollection(), pk);
|
|
186
183
|
await this._asyncFill(updatedModelData);
|
|
187
184
|
await this.postUpdate();
|
|
@@ -196,12 +193,13 @@ class RWSModel {
|
|
|
196
193
|
return this;
|
|
197
194
|
}
|
|
198
195
|
static async getModelAnnotations(constructor) {
|
|
199
|
-
return
|
|
196
|
+
return utils_1.ModelUtils.getModelAnnotations(constructor);
|
|
200
197
|
}
|
|
201
198
|
async preUpdate() {
|
|
202
199
|
return;
|
|
203
200
|
}
|
|
204
201
|
async postLoad() {
|
|
202
|
+
this.setPostLoadExecuted();
|
|
205
203
|
return;
|
|
206
204
|
}
|
|
207
205
|
async postUpdate() {
|
|
@@ -214,19 +212,19 @@ class RWSModel {
|
|
|
214
212
|
return;
|
|
215
213
|
}
|
|
216
214
|
static isSubclass(constructor, baseClass) {
|
|
217
|
-
return
|
|
215
|
+
return utils_1.ModelUtils.isSubclass(constructor, baseClass);
|
|
218
216
|
}
|
|
219
217
|
hasTimeSeries() {
|
|
220
|
-
return
|
|
218
|
+
return utils_1.TimeSeriesUtils.checkTimeSeries(this.constructor);
|
|
221
219
|
}
|
|
222
220
|
static checkTimeSeries(constructor) {
|
|
223
|
-
return
|
|
221
|
+
return utils_1.TimeSeriesUtils.checkTimeSeries(constructor);
|
|
224
222
|
}
|
|
225
223
|
async isDbVariable(variable) {
|
|
226
|
-
return
|
|
224
|
+
return utils_1.ModelUtils.checkDbVariable(this.constructor, variable);
|
|
227
225
|
}
|
|
228
226
|
static async checkDbVariable(constructor, variable) {
|
|
229
|
-
return
|
|
227
|
+
return utils_1.ModelUtils.checkDbVariable(constructor, variable);
|
|
230
228
|
}
|
|
231
229
|
sanitizeDBData(data) {
|
|
232
230
|
const dataKeys = Object.keys(data);
|
|
@@ -244,13 +242,13 @@ class RWSModel {
|
|
|
244
242
|
return await this.services.dbService.watchCollection(collection, preRun);
|
|
245
243
|
}
|
|
246
244
|
static async findOneBy(findParams) {
|
|
247
|
-
return await
|
|
245
|
+
return await utils_1.FindUtils.findOneBy(this, findParams);
|
|
248
246
|
}
|
|
249
247
|
static async find(id, findParams = null) {
|
|
250
|
-
return await
|
|
248
|
+
return await utils_1.FindUtils.find(this, id, findParams);
|
|
251
249
|
}
|
|
252
250
|
static async findBy(findParams) {
|
|
253
|
-
return await
|
|
251
|
+
return await utils_1.FindUtils.findBy(this, findParams);
|
|
254
252
|
}
|
|
255
253
|
static async delete(conditions) {
|
|
256
254
|
const collection = Reflect.get(this, '_collection');
|
|
@@ -277,7 +275,7 @@ class RWSModel {
|
|
|
277
275
|
return RWSModel.loadModels();
|
|
278
276
|
}
|
|
279
277
|
checkRelDisabled(key) {
|
|
280
|
-
return
|
|
278
|
+
return utils_1.RelationUtils.checkRelDisabled(this, key);
|
|
281
279
|
}
|
|
282
280
|
static setServices(services) {
|
|
283
281
|
this.allModels = services.configService.get('db_models');
|
|
@@ -292,8 +290,8 @@ class RWSModel {
|
|
|
292
290
|
static getDb() {
|
|
293
291
|
return this.services.dbService;
|
|
294
292
|
}
|
|
295
|
-
async reload() {
|
|
296
|
-
const pk =
|
|
293
|
+
async reload(inPostLoad = false) {
|
|
294
|
+
const pk = utils_1.ModelUtils.findPrimaryKeyFields(this.constructor);
|
|
297
295
|
const where = {};
|
|
298
296
|
if (Array.isArray(pk)) {
|
|
299
297
|
for (const pkElem of pk) {
|
|
@@ -303,7 +301,7 @@ class RWSModel {
|
|
|
303
301
|
else {
|
|
304
302
|
where[pk] = this[pk];
|
|
305
303
|
}
|
|
306
|
-
return await
|
|
304
|
+
return await utils_1.FindUtils.findOneBy(this.constructor, { conditions: where, cancelPostLoad: inPostLoad });
|
|
307
305
|
}
|
|
308
306
|
}
|
|
309
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>;
|