@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
|
@@ -1,88 +1,149 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.FindUtils = void 0;
|
|
7
|
+
const LoadingContext_1 = require("./LoadingContext");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
function circularReferenceWarning(modelType, id) {
|
|
10
|
+
console.warn(chalk_1.default.yellow(`Circular reference detected: ${modelType}:${id} is already being loaded. Breaking cycle.`));
|
|
11
|
+
}
|
|
4
12
|
class FindUtils {
|
|
5
13
|
static async findOneBy(opModel, findParams) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
// Wrap in new execution context to ensure clean loading stack per operation
|
|
15
|
+
return LoadingContext_1.LoadingContext.withNewExecutionContext(async () => {
|
|
16
|
+
const conditions = findParams?.conditions ?? {};
|
|
17
|
+
const ordering = findParams?.ordering ?? null;
|
|
18
|
+
const fields = findParams?.fields ?? null;
|
|
19
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
20
|
+
const fullData = findParams?.fullData ?? false;
|
|
21
|
+
opModel.checkForInclusionWithThrow('');
|
|
22
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
23
|
+
const dbData = await opModel.services.dbService.findOneBy(collection, conditions, fields, ordering);
|
|
24
|
+
if (dbData) {
|
|
25
|
+
const modelType = opModel.name;
|
|
26
|
+
const id = dbData.id;
|
|
27
|
+
// Check if this model is already being loaded to prevent circular references
|
|
28
|
+
if (LoadingContext_1.LoadingContext.isLoading(modelType, id)) {
|
|
29
|
+
circularReferenceWarning(modelType, id);
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return await LoadingContext_1.LoadingContext.withLoadingContext(modelType, id, async () => {
|
|
33
|
+
const inst = new opModel();
|
|
34
|
+
const loaded = await inst._asyncFill(dbData, fullData, allowRelations, findParams?.cancelPostLoad ? false : true);
|
|
35
|
+
return loaded;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
});
|
|
20
40
|
}
|
|
21
41
|
static async find(opModel, id, findParams = null) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
// Wrap in new execution context to ensure clean loading stack per operation
|
|
43
|
+
return LoadingContext_1.LoadingContext.withNewExecutionContext(async () => {
|
|
44
|
+
const ordering = findParams?.ordering ?? null;
|
|
45
|
+
const fields = findParams?.fields ?? null;
|
|
46
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
47
|
+
const fullData = findParams?.fullData ?? false;
|
|
48
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
49
|
+
opModel.checkForInclusionWithThrow(opModel.name);
|
|
50
|
+
const dbData = await opModel.services.dbService.findOneBy(collection, { id }, fields, ordering);
|
|
51
|
+
if (dbData) {
|
|
52
|
+
const modelType = opModel.name;
|
|
53
|
+
// Check if this model is already being loaded to prevent circular references
|
|
54
|
+
if (LoadingContext_1.LoadingContext.isLoading(modelType, id)) {
|
|
55
|
+
circularReferenceWarning(modelType, id);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return await LoadingContext_1.LoadingContext.withLoadingContext(modelType, id, async () => {
|
|
59
|
+
const inst = new opModel();
|
|
60
|
+
const loaded = await inst._asyncFill(dbData, fullData, allowRelations, findParams?.cancelPostLoad ? false : true);
|
|
61
|
+
return loaded;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
});
|
|
35
66
|
}
|
|
36
67
|
static async findBy(opModel, findParams) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
68
|
+
// Wrap in new execution context to ensure clean loading stack per operation
|
|
69
|
+
return LoadingContext_1.LoadingContext.withNewExecutionContext(async () => {
|
|
70
|
+
const conditions = findParams?.conditions ?? {};
|
|
71
|
+
const ordering = findParams?.ordering ?? null;
|
|
72
|
+
const fields = findParams?.fields ?? null;
|
|
73
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
74
|
+
const fullData = findParams?.fullData ?? false;
|
|
75
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
76
|
+
opModel.checkForInclusionWithThrow(opModel.name);
|
|
77
|
+
try {
|
|
78
|
+
const paginateParams = findParams?.pagination ? findParams?.pagination : undefined;
|
|
79
|
+
const dbData = await opModel.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
80
|
+
if (dbData.length) {
|
|
81
|
+
const instanced = [];
|
|
82
|
+
for (const data of dbData) {
|
|
83
|
+
const modelType = opModel.name;
|
|
84
|
+
const id = data.id;
|
|
85
|
+
// Check if this model is already being loaded to prevent circular references
|
|
86
|
+
if (LoadingContext_1.LoadingContext.isLoading(modelType, id)) {
|
|
87
|
+
circularReferenceWarning(modelType, id);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const loaded = await LoadingContext_1.LoadingContext.withLoadingContext(modelType, id, async () => {
|
|
91
|
+
const inst = new opModel();
|
|
92
|
+
return await inst._asyncFill(data, fullData, allowRelations, findParams?.cancelPostLoad ? false : true);
|
|
93
|
+
});
|
|
94
|
+
if (loaded) {
|
|
95
|
+
instanced.push(loaded);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return instanced;
|
|
52
99
|
}
|
|
53
|
-
return
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
catch (rwsError) {
|
|
103
|
+
console.error(rwsError);
|
|
104
|
+
throw rwsError;
|
|
54
105
|
}
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
catch (rwsError) {
|
|
58
|
-
console.error(rwsError);
|
|
59
|
-
throw rwsError;
|
|
60
|
-
}
|
|
106
|
+
});
|
|
61
107
|
}
|
|
62
108
|
static async paginate(opModel, paginateParams, findParams) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
109
|
+
// Wrap in new execution context to ensure clean loading stack per operation
|
|
110
|
+
return LoadingContext_1.LoadingContext.withNewExecutionContext(async () => {
|
|
111
|
+
const conditions = findParams?.conditions ?? {};
|
|
112
|
+
const ordering = findParams?.ordering ?? null;
|
|
113
|
+
const fields = findParams?.fields ?? null;
|
|
114
|
+
const allowRelations = findParams?.allowRelations ?? true;
|
|
115
|
+
const fullData = findParams?.fullData ?? false;
|
|
116
|
+
const collection = Reflect.get(opModel, '_collection');
|
|
117
|
+
opModel.checkForInclusionWithThrow(opModel.name);
|
|
118
|
+
try {
|
|
119
|
+
const dbData = await opModel.services.dbService.findBy(collection, conditions, fields, ordering, paginateParams);
|
|
120
|
+
if (dbData.length) {
|
|
121
|
+
const instanced = [];
|
|
122
|
+
for (const data of dbData) {
|
|
123
|
+
const modelType = opModel.name;
|
|
124
|
+
const id = data.id;
|
|
125
|
+
// Check if this model is already being loaded to prevent circular references
|
|
126
|
+
if (LoadingContext_1.LoadingContext.isLoading(modelType, id)) {
|
|
127
|
+
circularReferenceWarning(modelType, id);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const loaded = await LoadingContext_1.LoadingContext.withLoadingContext(modelType, id, async () => {
|
|
131
|
+
const inst = new opModel();
|
|
132
|
+
return await inst._asyncFill(data, fullData, allowRelations, findParams?.cancelPostLoad ? false : true);
|
|
133
|
+
});
|
|
134
|
+
if (loaded) {
|
|
135
|
+
instanced.push(loaded);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return instanced;
|
|
77
139
|
}
|
|
78
|
-
return
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
catch (rwsError) {
|
|
143
|
+
console.error(rwsError);
|
|
144
|
+
throw rwsError;
|
|
79
145
|
}
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
catch (rwsError) {
|
|
83
|
-
console.error(rwsError);
|
|
84
|
-
throw rwsError;
|
|
85
|
-
}
|
|
146
|
+
});
|
|
86
147
|
}
|
|
87
148
|
}
|
|
88
149
|
exports.FindUtils = FindUtils;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LoadingContext - Prevents circular references during model loading by tracking
|
|
3
|
+
* the chain of models currently being loaded per execution context
|
|
4
|
+
*/
|
|
5
|
+
declare global {
|
|
6
|
+
var __currentExecutionContext: object | undefined;
|
|
7
|
+
}
|
|
8
|
+
export declare class LoadingContext {
|
|
9
|
+
private static executionContexts;
|
|
10
|
+
private static defaultMaxDepth;
|
|
11
|
+
/**
|
|
12
|
+
* Get or create execution context identifier
|
|
13
|
+
*/
|
|
14
|
+
private static getExecutionContext;
|
|
15
|
+
/**
|
|
16
|
+
* Create a new execution context for an operation
|
|
17
|
+
*/
|
|
18
|
+
static withNewExecutionContext<T>(fn: () => Promise<T>): Promise<T>;
|
|
19
|
+
/**
|
|
20
|
+
* Get the loading stack for current execution context
|
|
21
|
+
*/
|
|
22
|
+
private static getLoadingStackInternal;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a model with specific ID is currently being loaded
|
|
25
|
+
*/
|
|
26
|
+
static isLoading(modelType: string, id: string | number): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Mark a model as currently being loaded
|
|
29
|
+
*/
|
|
30
|
+
static startLoading(modelType: string, id: string | number): void;
|
|
31
|
+
/**
|
|
32
|
+
* Mark a model as finished loading
|
|
33
|
+
*/
|
|
34
|
+
static finishLoading(modelType: string, id: string | number): void;
|
|
35
|
+
/**
|
|
36
|
+
* Get current loading stack for debugging
|
|
37
|
+
*/
|
|
38
|
+
static getLoadingStack(): string[];
|
|
39
|
+
/**
|
|
40
|
+
* Clear the entire loading stack for current context
|
|
41
|
+
*/
|
|
42
|
+
static clearStack(): void;
|
|
43
|
+
/**
|
|
44
|
+
* Set default maximum loading depth
|
|
45
|
+
*/
|
|
46
|
+
static setDefaultMaxDepth(depth: number): void;
|
|
47
|
+
/**
|
|
48
|
+
* Create a unique key for model type and ID
|
|
49
|
+
*/
|
|
50
|
+
private static createKey;
|
|
51
|
+
/**
|
|
52
|
+
* Execute a function with loading context protection
|
|
53
|
+
* Automatically manages start/finish loading calls
|
|
54
|
+
*/
|
|
55
|
+
static withLoadingContext<T>(modelType: string, id: string | number, fn: () => Promise<T>): Promise<T>;
|
|
56
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LoadingContext - Prevents circular references during model loading by tracking
|
|
4
|
+
* the chain of models currently being loaded per execution context
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.LoadingContext = void 0;
|
|
8
|
+
class LoadingContext {
|
|
9
|
+
static executionContexts = new WeakMap();
|
|
10
|
+
static defaultMaxDepth = 10;
|
|
11
|
+
/**
|
|
12
|
+
* Get or create execution context identifier
|
|
13
|
+
*/
|
|
14
|
+
static getExecutionContext() {
|
|
15
|
+
// Use a simple object as execution context identifier
|
|
16
|
+
// In a real-world scenario, this could be tied to request context
|
|
17
|
+
if (!globalThis.__currentExecutionContext) {
|
|
18
|
+
globalThis.__currentExecutionContext = {};
|
|
19
|
+
}
|
|
20
|
+
return globalThis.__currentExecutionContext;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a new execution context for an operation
|
|
24
|
+
*/
|
|
25
|
+
static withNewExecutionContext(fn) {
|
|
26
|
+
const previousContext = globalThis.__currentExecutionContext;
|
|
27
|
+
try {
|
|
28
|
+
globalThis.__currentExecutionContext = {};
|
|
29
|
+
return fn();
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
globalThis.__currentExecutionContext = previousContext;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get the loading stack for current execution context
|
|
37
|
+
*/
|
|
38
|
+
static getLoadingStackInternal() {
|
|
39
|
+
const context = this.getExecutionContext();
|
|
40
|
+
if (!this.executionContexts.has(context)) {
|
|
41
|
+
this.executionContexts.set(context, new Set());
|
|
42
|
+
}
|
|
43
|
+
return this.executionContexts.get(context);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if a model with specific ID is currently being loaded
|
|
47
|
+
*/
|
|
48
|
+
static isLoading(modelType, id) {
|
|
49
|
+
const key = this.createKey(modelType, id);
|
|
50
|
+
const loadingStack = this.getLoadingStackInternal();
|
|
51
|
+
return loadingStack.has(key);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Mark a model as currently being loaded
|
|
55
|
+
*/
|
|
56
|
+
static startLoading(modelType, id) {
|
|
57
|
+
const key = this.createKey(modelType, id);
|
|
58
|
+
const loadingStack = this.getLoadingStackInternal();
|
|
59
|
+
// Check for maximum depth to prevent infinite chains
|
|
60
|
+
if (loadingStack.size >= this.defaultMaxDepth) {
|
|
61
|
+
const stackArray = Array.from(loadingStack);
|
|
62
|
+
throw new Error(`Maximum loading depth (${this.defaultMaxDepth}) exceeded. ` +
|
|
63
|
+
`Possible circular reference detected. Loading stack: ${stackArray.join(' -> ')} -> ${key}`);
|
|
64
|
+
}
|
|
65
|
+
loadingStack.add(key);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Mark a model as finished loading
|
|
69
|
+
*/
|
|
70
|
+
static finishLoading(modelType, id) {
|
|
71
|
+
const key = this.createKey(modelType, id);
|
|
72
|
+
const loadingStack = this.getLoadingStackInternal();
|
|
73
|
+
loadingStack.delete(key);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get current loading stack for debugging
|
|
77
|
+
*/
|
|
78
|
+
static getLoadingStack() {
|
|
79
|
+
const loadingStack = this.getLoadingStackInternal();
|
|
80
|
+
return Array.from(loadingStack);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Clear the entire loading stack for current context
|
|
84
|
+
*/
|
|
85
|
+
static clearStack() {
|
|
86
|
+
const loadingStack = this.getLoadingStackInternal();
|
|
87
|
+
loadingStack.clear();
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Set default maximum loading depth
|
|
91
|
+
*/
|
|
92
|
+
static setDefaultMaxDepth(depth) {
|
|
93
|
+
this.defaultMaxDepth = depth;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create a unique key for model type and ID
|
|
97
|
+
*/
|
|
98
|
+
static createKey(modelType, id) {
|
|
99
|
+
return `${modelType}:${id}`;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Execute a function with loading context protection
|
|
103
|
+
* Automatically manages start/finish loading calls
|
|
104
|
+
*/
|
|
105
|
+
static async withLoadingContext(modelType, id, fn) {
|
|
106
|
+
if (this.isLoading(modelType, id)) {
|
|
107
|
+
// If already loading, return null to break the cycle
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
this.startLoading(modelType, id);
|
|
111
|
+
try {
|
|
112
|
+
return await fn();
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
this.finishLoading(modelType, id);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.LoadingContext = LoadingContext;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.testLoadingContext = testLoadingContext;
|
|
4
|
+
const LoadingContext_1 = require("./LoadingContext");
|
|
5
|
+
/**
|
|
6
|
+
* Simple test to verify LoadingContext functionality
|
|
7
|
+
*/
|
|
8
|
+
async function testLoadingContext() {
|
|
9
|
+
console.log('Testing LoadingContext...');
|
|
10
|
+
// Test 1: Basic loading detection
|
|
11
|
+
console.log('Test 1: Basic loading detection');
|
|
12
|
+
console.log('Is User:1 loading?', LoadingContext_1.LoadingContext.isLoading('User', 1)); // Should be false
|
|
13
|
+
LoadingContext_1.LoadingContext.startLoading('User', 1);
|
|
14
|
+
console.log('Is User:1 loading?', LoadingContext_1.LoadingContext.isLoading('User', 1)); // Should be true
|
|
15
|
+
LoadingContext_1.LoadingContext.finishLoading('User', 1);
|
|
16
|
+
console.log('Is User:1 loading?', LoadingContext_1.LoadingContext.isLoading('User', 1)); // Should be false
|
|
17
|
+
// Test 2: Circular reference detection
|
|
18
|
+
console.log('\nTest 2: Circular reference detection');
|
|
19
|
+
try {
|
|
20
|
+
await LoadingContext_1.LoadingContext.withLoadingContext('User', 1, async () => {
|
|
21
|
+
console.log('Loading User:1...');
|
|
22
|
+
// Simulate trying to load the same model again (circular reference)
|
|
23
|
+
const result = await LoadingContext_1.LoadingContext.withLoadingContext('User', 1, async () => {
|
|
24
|
+
console.log('This should not execute - circular reference detected');
|
|
25
|
+
return 'should not reach here';
|
|
26
|
+
});
|
|
27
|
+
console.log('Circular reference result:', result); // Should be null
|
|
28
|
+
return 'User loaded successfully';
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error('Error in circular reference test:', error);
|
|
33
|
+
}
|
|
34
|
+
// Test 3: Maximum depth protection
|
|
35
|
+
console.log('\nTest 3: Maximum depth protection');
|
|
36
|
+
LoadingContext_1.LoadingContext.setMaxDepth(3);
|
|
37
|
+
try {
|
|
38
|
+
LoadingContext_1.LoadingContext.startLoading('Model1', 1);
|
|
39
|
+
LoadingContext_1.LoadingContext.startLoading('Model2', 2);
|
|
40
|
+
LoadingContext_1.LoadingContext.startLoading('Model3', 3);
|
|
41
|
+
// This should throw an error
|
|
42
|
+
LoadingContext_1.LoadingContext.startLoading('Model4', 4);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.log('Expected error caught:', error.message);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
LoadingContext_1.LoadingContext.clearStack();
|
|
49
|
+
}
|
|
50
|
+
console.log('LoadingContext tests completed!');
|
|
51
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { FindUtils } from './FindUtils';
|
|
2
|
+
export { HydrateUtils } from './HydrateUtils';
|
|
3
|
+
export { LoadingContext } from './LoadingContext';
|
|
4
|
+
export { ModelUtils } from './ModelUtils';
|
|
5
|
+
export { PaginationUtils } from './PaginationUtils';
|
|
6
|
+
export { RelationUtils } from './RelationUtils';
|
|
7
|
+
export { TimeSeriesUtils } from './TimeSeriesUtils';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TimeSeriesUtils = exports.RelationUtils = exports.PaginationUtils = exports.ModelUtils = exports.LoadingContext = exports.HydrateUtils = exports.FindUtils = void 0;
|
|
4
|
+
var FindUtils_1 = require("./FindUtils");
|
|
5
|
+
Object.defineProperty(exports, "FindUtils", { enumerable: true, get: function () { return FindUtils_1.FindUtils; } });
|
|
6
|
+
var HydrateUtils_1 = require("./HydrateUtils");
|
|
7
|
+
Object.defineProperty(exports, "HydrateUtils", { enumerable: true, get: function () { return HydrateUtils_1.HydrateUtils; } });
|
|
8
|
+
var LoadingContext_1 = require("./LoadingContext");
|
|
9
|
+
Object.defineProperty(exports, "LoadingContext", { enumerable: true, get: function () { return LoadingContext_1.LoadingContext; } });
|
|
10
|
+
var ModelUtils_1 = require("./ModelUtils");
|
|
11
|
+
Object.defineProperty(exports, "ModelUtils", { enumerable: true, get: function () { return ModelUtils_1.ModelUtils; } });
|
|
12
|
+
var PaginationUtils_1 = require("./PaginationUtils");
|
|
13
|
+
Object.defineProperty(exports, "PaginationUtils", { enumerable: true, get: function () { return PaginationUtils_1.PaginationUtils; } });
|
|
14
|
+
var RelationUtils_1 = require("./RelationUtils");
|
|
15
|
+
Object.defineProperty(exports, "RelationUtils", { enumerable: true, get: function () { return RelationUtils_1.RelationUtils; } });
|
|
16
|
+
var TimeSeriesUtils_1 = require("./TimeSeriesUtils");
|
|
17
|
+
Object.defineProperty(exports, "TimeSeriesUtils", { enumerable: true, get: function () { return TimeSeriesUtils_1.TimeSeriesUtils; } });
|
package/package.json
CHANGED
|
@@ -4,15 +4,16 @@ import { OpModelType } from '../interfaces/OpModelType';
|
|
|
4
4
|
import { TrackType } from '../../decorators';
|
|
5
5
|
import { FieldsHelper } from '../../helper/FieldsHelper';
|
|
6
6
|
import { FindByType, IPaginationParams } from '../../types/FindParams';
|
|
7
|
-
import { RelationUtils } from '../utils/RelationUtils';
|
|
8
|
-
|
|
9
|
-
import { TimeSeriesUtils } from '../utils/TimeSeriesUtils';
|
|
10
|
-
import { ModelUtils } from '../utils/ModelUtils';
|
|
11
|
-
// import timeSeriesModel from './TimeSeriesModel';
|
|
12
7
|
import { DBService } from '../../services/DBService';
|
|
13
8
|
import { ISuperTagData } from '../../decorators/RWSCollection';
|
|
14
|
-
import {
|
|
15
|
-
|
|
9
|
+
import {
|
|
10
|
+
RelationUtils,
|
|
11
|
+
TimeSeriesUtils,
|
|
12
|
+
ModelUtils,
|
|
13
|
+
HydrateUtils,
|
|
14
|
+
FindUtils,
|
|
15
|
+
LoadingContext
|
|
16
|
+
} from '../utils';
|
|
16
17
|
|
|
17
18
|
class RWSModel<T> implements IModel {
|
|
18
19
|
static services: IRWSModelServices = {};
|
|
@@ -137,9 +138,9 @@ class RWSModel<T> implements IModel {
|
|
|
137
138
|
// Process regular fields and time series
|
|
138
139
|
await HydrateUtils.hydrateDataFields(this, collections_to_models, relOneData, seriesHydrationfields, fullDataMode, data);
|
|
139
140
|
|
|
140
|
-
if(!this.isPostLoadExecuted() && postLoadExecute){
|
|
141
|
-
|
|
142
|
-
this.
|
|
141
|
+
if(!this.isPostLoadExecuted() && postLoadExecute){
|
|
142
|
+
|
|
143
|
+
await this.postLoad();
|
|
143
144
|
}
|
|
144
145
|
|
|
145
146
|
return this as any as T;
|
|
@@ -182,15 +183,16 @@ class RWSModel<T> implements IModel {
|
|
|
182
183
|
|
|
183
184
|
for (const key in (this as any)) {
|
|
184
185
|
if (await this.hasRelation(key)) {
|
|
185
|
-
|
|
186
|
+
if (this[key] === null) {
|
|
187
|
+
// For null relations, use disconnect or set to null
|
|
188
|
+
data[key] = {
|
|
189
|
+
disconnect: true
|
|
190
|
+
};
|
|
191
|
+
} else {
|
|
192
|
+
data[key] = this.bindRelation(key, this[key]);
|
|
193
|
+
}
|
|
186
194
|
|
|
187
|
-
|
|
188
|
-
const relationKey = await this.getRelationKey(key);
|
|
189
|
-
if(relationKey){
|
|
190
|
-
data[relationKey] = null;
|
|
191
|
-
delete data[key];
|
|
192
|
-
}
|
|
193
|
-
}
|
|
195
|
+
// Don't try to set the foreign key directly anymore
|
|
194
196
|
continue;
|
|
195
197
|
}
|
|
196
198
|
|
|
@@ -265,7 +267,8 @@ class RWSModel<T> implements IModel {
|
|
|
265
267
|
return;
|
|
266
268
|
}
|
|
267
269
|
|
|
268
|
-
public async postLoad(): Promise<void> {
|
|
270
|
+
public async postLoad(): Promise<void> {
|
|
271
|
+
this.setPostLoadExecuted();
|
|
269
272
|
return;
|
|
270
273
|
}
|
|
271
274
|
|
|
@@ -403,7 +406,7 @@ class RWSModel<T> implements IModel {
|
|
|
403
406
|
return this.services.dbService;
|
|
404
407
|
}
|
|
405
408
|
|
|
406
|
-
public async reload(): Promise<RWSModel<T> | null>
|
|
409
|
+
public async reload(inPostLoad = false): Promise<RWSModel<T> | null>
|
|
407
410
|
{
|
|
408
411
|
const pk = ModelUtils.findPrimaryKeyFields(this.constructor as OpModelType<T>);
|
|
409
412
|
const where: any = {};
|
|
@@ -416,7 +419,7 @@ class RWSModel<T> implements IModel {
|
|
|
416
419
|
where[pk as string] = this[pk as string]
|
|
417
420
|
}
|
|
418
421
|
|
|
419
|
-
return await FindUtils.findOneBy(this.constructor as OpModelType<any>, { conditions: where });
|
|
422
|
+
return await FindUtils.findOneBy(this.constructor as OpModelType<any>, { conditions: where, cancelPostLoad: inPostLoad });
|
|
420
423
|
}
|
|
421
424
|
}
|
|
422
425
|
|
|
@@ -11,7 +11,7 @@ export interface IModel {
|
|
|
11
11
|
save: () => Promise<this>;
|
|
12
12
|
getDb: () => DBService;
|
|
13
13
|
getCollection: () => string | null;
|
|
14
|
-
reload: () => Promise<RWSModel<any>>;
|
|
14
|
+
reload: (inPostLoad: boolean) => Promise<RWSModel<any>>;
|
|
15
15
|
delete: () => Promise<void>;
|
|
16
16
|
hasTimeSeries: () => boolean;
|
|
17
17
|
|