@hed-hog/core 0.0.301 → 0.0.302
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/integration/services/integration-link.service.d.ts +5 -1
- package/dist/integration/services/integration-link.service.d.ts.map +1 -1
- package/dist/integration/services/integration-link.service.js +141 -53
- package/dist/integration/services/integration-link.service.js.map +1 -1
- package/package.json +4 -4
- package/src/integration/services/integration-link.service.ts +190 -55
|
@@ -11,11 +11,15 @@ export interface CreateIntegrationLinkDto {
|
|
|
11
11
|
metadata?: Record<string, any>;
|
|
12
12
|
}
|
|
13
13
|
export interface IntegrationLinkPersistenceClient {
|
|
14
|
-
integrationLink
|
|
14
|
+
integrationLink?: PrismaService['integrationLink'];
|
|
15
|
+
integration_link?: PrismaService['integration_link'];
|
|
15
16
|
}
|
|
16
17
|
export declare class IntegrationLinkService {
|
|
17
18
|
private readonly prisma;
|
|
18
19
|
constructor(prisma: PrismaService);
|
|
20
|
+
private resolvePersistence;
|
|
21
|
+
private toDomainLink;
|
|
22
|
+
private toDatabaseId;
|
|
19
23
|
/**
|
|
20
24
|
* Create a link between entities from different modules
|
|
21
25
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-link.service.d.ts","sourceRoot":"","sources":["../../../src/integration/services/integration-link.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAErD,MAAM,WAAW,wBAAwB;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,gCAAgC;IAC/C,eAAe,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"integration-link.service.d.ts","sourceRoot":"","sources":["../../../src/integration/services/integration-link.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAErD,MAAM,WAAW,wBAAwB;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,gCAAgC;IAC/C,eAAe,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IACnD,gBAAgB,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;CACtD;AAyBD,qBACa,sBAAsB;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAElD,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,YAAY;IASpB;;OAEG;IACG,UAAU,CACd,GAAG,EAAE,wBAAwB,EAC7B,iBAAiB,CAAC,EAAE,gCAAgC,GACnD,OAAO,CAAC,eAAe,CAAC;IA8B3B;;OAEG;IACG,YAAY,CAChB,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,eAAe,EAAE,CAAC;IAqB7B;;OAEG;IACG,WAAW,CACf,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,eAAe,EAAE,CAAC;IAqB7B;;OAEG;IACG,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAWpE;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAS1D;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAS9D;;OAEG;IACG,iBAAiB,CACrB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAgDlC;;OAEG;IACG,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAM7D"}
|
|
@@ -12,111 +12,199 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.IntegrationLinkService = void 0;
|
|
13
13
|
const api_prisma_1 = require("@hed-hog/api-prisma");
|
|
14
14
|
const common_1 = require("@nestjs/common");
|
|
15
|
+
const types_1 = require("../types");
|
|
15
16
|
let IntegrationLinkService = class IntegrationLinkService {
|
|
16
17
|
constructor(prisma) {
|
|
17
18
|
this.prisma = prisma;
|
|
18
19
|
}
|
|
20
|
+
resolvePersistence(persistenceClient) {
|
|
21
|
+
var _a;
|
|
22
|
+
const client = (persistenceClient !== null && persistenceClient !== void 0 ? persistenceClient : this.prisma);
|
|
23
|
+
const delegate = (_a = client.integration_link) !== null && _a !== void 0 ? _a : client.integrationLink;
|
|
24
|
+
const useSnakeCase = !!client.integration_link;
|
|
25
|
+
if (!delegate) {
|
|
26
|
+
throw new Error('Integration link delegate is not available on the Prisma client.');
|
|
27
|
+
}
|
|
28
|
+
return { delegate, useSnakeCase };
|
|
29
|
+
}
|
|
30
|
+
toDomainLink(record) {
|
|
31
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
|
|
32
|
+
return {
|
|
33
|
+
id: String(record.id),
|
|
34
|
+
sourceModule: (_b = (_a = record.source_module) !== null && _a !== void 0 ? _a : record.sourceModule) !== null && _b !== void 0 ? _b : '',
|
|
35
|
+
sourceEntityType: (_d = (_c = record.source_entity_type) !== null && _c !== void 0 ? _c : record.sourceEntityType) !== null && _d !== void 0 ? _d : '',
|
|
36
|
+
sourceEntityId: (_f = (_e = record.source_entity_id) !== null && _e !== void 0 ? _e : record.sourceEntityId) !== null && _f !== void 0 ? _f : '',
|
|
37
|
+
targetModule: (_h = (_g = record.target_module) !== null && _g !== void 0 ? _g : record.targetModule) !== null && _h !== void 0 ? _h : '',
|
|
38
|
+
targetEntityType: (_k = (_j = record.target_entity_type) !== null && _j !== void 0 ? _j : record.targetEntityType) !== null && _k !== void 0 ? _k : '',
|
|
39
|
+
targetEntityId: (_m = (_l = record.target_entity_id) !== null && _l !== void 0 ? _l : record.targetEntityId) !== null && _m !== void 0 ? _m : '',
|
|
40
|
+
linkType: ((_p = (_o = record.link_type) !== null && _o !== void 0 ? _o : record.linkType) !== null && _p !== void 0 ? _p : types_1.LinkType.REFERENCE),
|
|
41
|
+
metadata: (_q = record.metadata) !== null && _q !== void 0 ? _q : null,
|
|
42
|
+
createdAt: (_s = (_r = record.created_at) !== null && _r !== void 0 ? _r : record.createdAt) !== null && _s !== void 0 ? _s : new Date(),
|
|
43
|
+
updatedAt: (_u = (_t = record.updated_at) !== null && _t !== void 0 ? _t : record.updatedAt) !== null && _u !== void 0 ? _u : new Date(),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
toDatabaseId(linkId) {
|
|
47
|
+
if (typeof linkId === 'number') {
|
|
48
|
+
return linkId;
|
|
49
|
+
}
|
|
50
|
+
const numericId = Number(linkId);
|
|
51
|
+
return Number.isNaN(numericId) ? linkId : numericId;
|
|
52
|
+
}
|
|
19
53
|
/**
|
|
20
54
|
* Create a link between entities from different modules
|
|
21
55
|
*/
|
|
22
56
|
async createLink(dto, persistenceClient) {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
data:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
57
|
+
const { delegate, useSnakeCase } = this.resolvePersistence(persistenceClient);
|
|
58
|
+
const record = await delegate.create({
|
|
59
|
+
data: useSnakeCase
|
|
60
|
+
? {
|
|
61
|
+
source_module: dto.sourceModule,
|
|
62
|
+
source_entity_type: dto.sourceEntityType,
|
|
63
|
+
source_entity_id: dto.sourceEntityId,
|
|
64
|
+
target_module: dto.targetModule,
|
|
65
|
+
target_entity_type: dto.targetEntityType,
|
|
66
|
+
target_entity_id: dto.targetEntityId,
|
|
67
|
+
link_type: dto.linkType,
|
|
68
|
+
metadata: dto.metadata || null,
|
|
69
|
+
}
|
|
70
|
+
: {
|
|
71
|
+
sourceModule: dto.sourceModule,
|
|
72
|
+
sourceEntityType: dto.sourceEntityType,
|
|
73
|
+
sourceEntityId: dto.sourceEntityId,
|
|
74
|
+
targetModule: dto.targetModule,
|
|
75
|
+
targetEntityType: dto.targetEntityType,
|
|
76
|
+
targetEntityId: dto.targetEntityId,
|
|
77
|
+
linkType: dto.linkType,
|
|
78
|
+
metadata: dto.metadata || null,
|
|
79
|
+
},
|
|
35
80
|
});
|
|
81
|
+
return this.toDomainLink(record);
|
|
36
82
|
}
|
|
37
83
|
/**
|
|
38
84
|
* Find all links originating from a source entity
|
|
39
85
|
*/
|
|
40
86
|
async findOutbound(sourceModule, sourceEntityType, sourceEntityId) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
87
|
+
const { delegate, useSnakeCase } = this.resolvePersistence();
|
|
88
|
+
const records = await delegate.findMany({
|
|
89
|
+
where: useSnakeCase
|
|
90
|
+
? {
|
|
91
|
+
source_module: sourceModule,
|
|
92
|
+
source_entity_type: sourceEntityType,
|
|
93
|
+
source_entity_id: sourceEntityId,
|
|
94
|
+
}
|
|
95
|
+
: {
|
|
96
|
+
sourceModule,
|
|
97
|
+
sourceEntityType,
|
|
98
|
+
sourceEntityId,
|
|
99
|
+
},
|
|
47
100
|
});
|
|
101
|
+
return records.map((record) => this.toDomainLink(record));
|
|
48
102
|
}
|
|
49
103
|
/**
|
|
50
104
|
* Find all links terminating at a target entity
|
|
51
105
|
*/
|
|
52
106
|
async findInbound(targetModule, targetEntityType, targetEntityId) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
107
|
+
const { delegate, useSnakeCase } = this.resolvePersistence();
|
|
108
|
+
const records = await delegate.findMany({
|
|
109
|
+
where: useSnakeCase
|
|
110
|
+
? {
|
|
111
|
+
target_module: targetModule,
|
|
112
|
+
target_entity_type: targetEntityType,
|
|
113
|
+
target_entity_id: targetEntityId,
|
|
114
|
+
}
|
|
115
|
+
: {
|
|
116
|
+
targetModule,
|
|
117
|
+
targetEntityType,
|
|
118
|
+
targetEntityId,
|
|
119
|
+
},
|
|
59
120
|
});
|
|
121
|
+
return records.map((record) => this.toDomainLink(record));
|
|
60
122
|
}
|
|
61
123
|
/**
|
|
62
124
|
* Find links of a specific type
|
|
63
125
|
*/
|
|
64
126
|
async findByLinkType(linkType) {
|
|
65
|
-
|
|
66
|
-
|
|
127
|
+
const { delegate, useSnakeCase } = this.resolvePersistence();
|
|
128
|
+
const records = await delegate.findMany({
|
|
129
|
+
where: useSnakeCase ? { link_type: linkType } : { linkType },
|
|
67
130
|
});
|
|
131
|
+
return records.map((record) => this.toDomainLink(record));
|
|
68
132
|
}
|
|
69
133
|
/**
|
|
70
134
|
* Delete a link
|
|
71
135
|
*/
|
|
72
136
|
async deleteLink(linkId) {
|
|
73
|
-
|
|
74
|
-
|
|
137
|
+
const { delegate } = this.resolvePersistence();
|
|
138
|
+
const record = await delegate.delete({
|
|
139
|
+
where: { id: this.toDatabaseId(linkId) },
|
|
75
140
|
});
|
|
141
|
+
return this.toDomainLink(record);
|
|
76
142
|
}
|
|
77
143
|
/**
|
|
78
144
|
* Get link by ID
|
|
79
145
|
*/
|
|
80
146
|
async getById(linkId) {
|
|
81
|
-
|
|
82
|
-
|
|
147
|
+
const { delegate } = this.resolvePersistence();
|
|
148
|
+
const record = await delegate.findUnique({
|
|
149
|
+
where: { id: this.toDatabaseId(linkId) },
|
|
83
150
|
});
|
|
151
|
+
return record ? this.toDomainLink(record) : null;
|
|
84
152
|
}
|
|
85
153
|
/**
|
|
86
154
|
* Find bidirectional link between two entities
|
|
87
155
|
*/
|
|
88
156
|
async findBidirectional(module1, entity1Type, entity1Id, module2, entity2Type, entity2Id) {
|
|
89
|
-
|
|
90
|
-
const
|
|
157
|
+
const { delegate, useSnakeCase } = this.resolvePersistence();
|
|
158
|
+
const record = await delegate.findFirst({
|
|
91
159
|
where: {
|
|
92
|
-
OR:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
160
|
+
OR: useSnakeCase
|
|
161
|
+
? [
|
|
162
|
+
{
|
|
163
|
+
source_module: module1,
|
|
164
|
+
source_entity_type: entity1Type,
|
|
165
|
+
source_entity_id: entity1Id,
|
|
166
|
+
target_module: module2,
|
|
167
|
+
target_entity_type: entity2Type,
|
|
168
|
+
target_entity_id: entity2Id,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
source_module: module2,
|
|
172
|
+
source_entity_type: entity2Type,
|
|
173
|
+
source_entity_id: entity2Id,
|
|
174
|
+
target_module: module1,
|
|
175
|
+
target_entity_type: entity1Type,
|
|
176
|
+
target_entity_id: entity1Id,
|
|
177
|
+
},
|
|
178
|
+
]
|
|
179
|
+
: [
|
|
180
|
+
{
|
|
181
|
+
sourceModule: module1,
|
|
182
|
+
sourceEntityType: entity1Type,
|
|
183
|
+
sourceEntityId: entity1Id,
|
|
184
|
+
targetModule: module2,
|
|
185
|
+
targetEntityType: entity2Type,
|
|
186
|
+
targetEntityId: entity2Id,
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
sourceModule: module2,
|
|
190
|
+
sourceEntityType: entity2Type,
|
|
191
|
+
sourceEntityId: entity2Id,
|
|
192
|
+
targetModule: module1,
|
|
193
|
+
targetEntityType: entity1Type,
|
|
194
|
+
targetEntityId: entity1Id,
|
|
195
|
+
},
|
|
196
|
+
],
|
|
110
197
|
},
|
|
111
198
|
});
|
|
112
|
-
return
|
|
199
|
+
return record ? this.toDomainLink(record) : null;
|
|
113
200
|
}
|
|
114
201
|
/**
|
|
115
202
|
* Count links from a module
|
|
116
203
|
*/
|
|
117
204
|
async countFromModule(sourceModule) {
|
|
118
|
-
|
|
119
|
-
|
|
205
|
+
const { delegate, useSnakeCase } = this.resolvePersistence();
|
|
206
|
+
return delegate.count({
|
|
207
|
+
where: useSnakeCase ? { source_module: sourceModule } : { sourceModule },
|
|
120
208
|
});
|
|
121
209
|
}
|
|
122
210
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-link.service.js","sourceRoot":"","sources":["../../../src/integration/services/integration-link.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oDAAoD;AACpD,2CAA4C;
|
|
1
|
+
{"version":3,"file":"integration-link.service.js","sourceRoot":"","sources":["../../../src/integration/services/integration-link.service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.302",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
"speakeasy": "^2.0.0",
|
|
32
32
|
"uuid": "^11.1.0",
|
|
33
33
|
"@hed-hog/api": "0.0.6",
|
|
34
|
-
"@hed-hog/api-types": "0.0.1",
|
|
35
34
|
"@hed-hog/api-mail": "0.0.9",
|
|
35
|
+
"@hed-hog/api-types": "0.0.1",
|
|
36
|
+
"@hed-hog/api-prisma": "0.0.6",
|
|
36
37
|
"@hed-hog/api-locale": "0.0.14",
|
|
37
|
-
"@hed-hog/api-pagination": "0.0.7"
|
|
38
|
-
"@hed-hog/api-prisma": "0.0.6"
|
|
38
|
+
"@hed-hog/api-pagination": "0.0.7"
|
|
39
39
|
},
|
|
40
40
|
"exports": {
|
|
41
41
|
".": {
|
|
@@ -14,13 +14,81 @@ export interface CreateIntegrationLinkDto {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export interface IntegrationLinkPersistenceClient {
|
|
17
|
-
integrationLink
|
|
17
|
+
integrationLink?: PrismaService['integrationLink'];
|
|
18
|
+
integration_link?: PrismaService['integration_link'];
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
type IntegrationLinkRecord = {
|
|
22
|
+
id: number | string;
|
|
23
|
+
source_module?: string;
|
|
24
|
+
source_entity_type?: string;
|
|
25
|
+
source_entity_id?: string;
|
|
26
|
+
target_module?: string;
|
|
27
|
+
target_entity_type?: string;
|
|
28
|
+
target_entity_id?: string;
|
|
29
|
+
link_type?: LinkType | string;
|
|
30
|
+
created_at?: Date;
|
|
31
|
+
updated_at?: Date;
|
|
32
|
+
sourceModule?: string;
|
|
33
|
+
sourceEntityType?: string;
|
|
34
|
+
sourceEntityId?: string;
|
|
35
|
+
targetModule?: string;
|
|
36
|
+
targetEntityType?: string;
|
|
37
|
+
targetEntityId?: string;
|
|
38
|
+
linkType?: LinkType | string;
|
|
39
|
+
metadata?: Record<string, any> | null;
|
|
40
|
+
createdAt?: Date;
|
|
41
|
+
updatedAt?: Date;
|
|
42
|
+
};
|
|
43
|
+
|
|
20
44
|
@Injectable()
|
|
21
45
|
export class IntegrationLinkService {
|
|
22
46
|
constructor(private readonly prisma: PrismaService) {}
|
|
23
47
|
|
|
48
|
+
private resolvePersistence(
|
|
49
|
+
persistenceClient?: IntegrationLinkPersistenceClient,
|
|
50
|
+
) {
|
|
51
|
+
const client = (persistenceClient ?? this.prisma) as PrismaService &
|
|
52
|
+
IntegrationLinkPersistenceClient;
|
|
53
|
+
const delegate = client.integration_link ?? client.integrationLink;
|
|
54
|
+
const useSnakeCase = !!client.integration_link;
|
|
55
|
+
|
|
56
|
+
if (!delegate) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
'Integration link delegate is not available on the Prisma client.',
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return { delegate, useSnakeCase };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private toDomainLink(record: IntegrationLinkRecord): IntegrationLink {
|
|
66
|
+
return {
|
|
67
|
+
id: String(record.id),
|
|
68
|
+
sourceModule: record.source_module ?? record.sourceModule ?? '',
|
|
69
|
+
sourceEntityType:
|
|
70
|
+
record.source_entity_type ?? record.sourceEntityType ?? '',
|
|
71
|
+
sourceEntityId: record.source_entity_id ?? record.sourceEntityId ?? '',
|
|
72
|
+
targetModule: record.target_module ?? record.targetModule ?? '',
|
|
73
|
+
targetEntityType:
|
|
74
|
+
record.target_entity_type ?? record.targetEntityType ?? '',
|
|
75
|
+
targetEntityId: record.target_entity_id ?? record.targetEntityId ?? '',
|
|
76
|
+
linkType: (record.link_type ?? record.linkType ?? LinkType.REFERENCE) as LinkType,
|
|
77
|
+
metadata: record.metadata ?? null,
|
|
78
|
+
createdAt: record.created_at ?? record.createdAt ?? new Date(),
|
|
79
|
+
updatedAt: record.updated_at ?? record.updatedAt ?? new Date(),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private toDatabaseId(linkId: string | number) {
|
|
84
|
+
if (typeof linkId === 'number') {
|
|
85
|
+
return linkId;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const numericId = Number(linkId);
|
|
89
|
+
return Number.isNaN(numericId) ? linkId : numericId;
|
|
90
|
+
}
|
|
91
|
+
|
|
24
92
|
/**
|
|
25
93
|
* Create a link between entities from different modules
|
|
26
94
|
*/
|
|
@@ -28,20 +96,33 @@ export class IntegrationLinkService {
|
|
|
28
96
|
dto: CreateIntegrationLinkDto,
|
|
29
97
|
persistenceClient?: IntegrationLinkPersistenceClient,
|
|
30
98
|
): Promise<IntegrationLink> {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
data:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
99
|
+
const { delegate, useSnakeCase } = this.resolvePersistence(persistenceClient);
|
|
100
|
+
|
|
101
|
+
const record = await delegate.create({
|
|
102
|
+
data: useSnakeCase
|
|
103
|
+
? {
|
|
104
|
+
source_module: dto.sourceModule,
|
|
105
|
+
source_entity_type: dto.sourceEntityType,
|
|
106
|
+
source_entity_id: dto.sourceEntityId,
|
|
107
|
+
target_module: dto.targetModule,
|
|
108
|
+
target_entity_type: dto.targetEntityType,
|
|
109
|
+
target_entity_id: dto.targetEntityId,
|
|
110
|
+
link_type: dto.linkType,
|
|
111
|
+
metadata: dto.metadata || null,
|
|
112
|
+
}
|
|
113
|
+
: {
|
|
114
|
+
sourceModule: dto.sourceModule,
|
|
115
|
+
sourceEntityType: dto.sourceEntityType,
|
|
116
|
+
sourceEntityId: dto.sourceEntityId,
|
|
117
|
+
targetModule: dto.targetModule,
|
|
118
|
+
targetEntityType: dto.targetEntityType,
|
|
119
|
+
targetEntityId: dto.targetEntityId,
|
|
120
|
+
linkType: dto.linkType,
|
|
121
|
+
metadata: dto.metadata || null,
|
|
122
|
+
},
|
|
44
123
|
});
|
|
124
|
+
|
|
125
|
+
return this.toDomainLink(record as IntegrationLinkRecord);
|
|
45
126
|
}
|
|
46
127
|
|
|
47
128
|
/**
|
|
@@ -52,13 +133,24 @@ export class IntegrationLinkService {
|
|
|
52
133
|
sourceEntityType: string,
|
|
53
134
|
sourceEntityId: string,
|
|
54
135
|
): Promise<IntegrationLink[]> {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
136
|
+
const { delegate, useSnakeCase } = this.resolvePersistence();
|
|
137
|
+
const records = await delegate.findMany({
|
|
138
|
+
where: useSnakeCase
|
|
139
|
+
? {
|
|
140
|
+
source_module: sourceModule,
|
|
141
|
+
source_entity_type: sourceEntityType,
|
|
142
|
+
source_entity_id: sourceEntityId,
|
|
143
|
+
}
|
|
144
|
+
: {
|
|
145
|
+
sourceModule,
|
|
146
|
+
sourceEntityType,
|
|
147
|
+
sourceEntityId,
|
|
148
|
+
},
|
|
61
149
|
});
|
|
150
|
+
|
|
151
|
+
return records.map((record: IntegrationLinkRecord) =>
|
|
152
|
+
this.toDomainLink(record),
|
|
153
|
+
);
|
|
62
154
|
}
|
|
63
155
|
|
|
64
156
|
/**
|
|
@@ -69,40 +161,62 @@ export class IntegrationLinkService {
|
|
|
69
161
|
targetEntityType: string,
|
|
70
162
|
targetEntityId: string,
|
|
71
163
|
): Promise<IntegrationLink[]> {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
164
|
+
const { delegate, useSnakeCase } = this.resolvePersistence();
|
|
165
|
+
const records = await delegate.findMany({
|
|
166
|
+
where: useSnakeCase
|
|
167
|
+
? {
|
|
168
|
+
target_module: targetModule,
|
|
169
|
+
target_entity_type: targetEntityType,
|
|
170
|
+
target_entity_id: targetEntityId,
|
|
171
|
+
}
|
|
172
|
+
: {
|
|
173
|
+
targetModule,
|
|
174
|
+
targetEntityType,
|
|
175
|
+
targetEntityId,
|
|
176
|
+
},
|
|
78
177
|
});
|
|
178
|
+
|
|
179
|
+
return records.map((record: IntegrationLinkRecord) =>
|
|
180
|
+
this.toDomainLink(record),
|
|
181
|
+
);
|
|
79
182
|
}
|
|
80
183
|
|
|
81
184
|
/**
|
|
82
185
|
* Find links of a specific type
|
|
83
186
|
*/
|
|
84
187
|
async findByLinkType(linkType: LinkType): Promise<IntegrationLink[]> {
|
|
85
|
-
|
|
86
|
-
|
|
188
|
+
const { delegate, useSnakeCase } = this.resolvePersistence();
|
|
189
|
+
const records = await delegate.findMany({
|
|
190
|
+
where: useSnakeCase ? { link_type: linkType } : { linkType },
|
|
87
191
|
});
|
|
192
|
+
|
|
193
|
+
return records.map((record: IntegrationLinkRecord) =>
|
|
194
|
+
this.toDomainLink(record),
|
|
195
|
+
);
|
|
88
196
|
}
|
|
89
197
|
|
|
90
198
|
/**
|
|
91
199
|
* Delete a link
|
|
92
200
|
*/
|
|
93
201
|
async deleteLink(linkId: string): Promise<IntegrationLink> {
|
|
94
|
-
|
|
95
|
-
|
|
202
|
+
const { delegate } = this.resolvePersistence();
|
|
203
|
+
const record = await delegate.delete({
|
|
204
|
+
where: { id: this.toDatabaseId(linkId) },
|
|
96
205
|
});
|
|
206
|
+
|
|
207
|
+
return this.toDomainLink(record as IntegrationLinkRecord);
|
|
97
208
|
}
|
|
98
209
|
|
|
99
210
|
/**
|
|
100
211
|
* Get link by ID
|
|
101
212
|
*/
|
|
102
213
|
async getById(linkId: string): Promise<IntegrationLink | null> {
|
|
103
|
-
|
|
104
|
-
|
|
214
|
+
const { delegate } = this.resolvePersistence();
|
|
215
|
+
const record = await delegate.findUnique({
|
|
216
|
+
where: { id: this.toDatabaseId(linkId) },
|
|
105
217
|
});
|
|
218
|
+
|
|
219
|
+
return record ? this.toDomainLink(record as IntegrationLinkRecord) : null;
|
|
106
220
|
}
|
|
107
221
|
|
|
108
222
|
/**
|
|
@@ -116,39 +230,60 @@ export class IntegrationLinkService {
|
|
|
116
230
|
entity2Type: string,
|
|
117
231
|
entity2Id: string,
|
|
118
232
|
): Promise<IntegrationLink | null> {
|
|
119
|
-
|
|
120
|
-
|
|
233
|
+
const { delegate, useSnakeCase } = this.resolvePersistence();
|
|
234
|
+
|
|
235
|
+
const record = await delegate.findFirst({
|
|
121
236
|
where: {
|
|
122
|
-
OR:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
237
|
+
OR: useSnakeCase
|
|
238
|
+
? [
|
|
239
|
+
{
|
|
240
|
+
source_module: module1,
|
|
241
|
+
source_entity_type: entity1Type,
|
|
242
|
+
source_entity_id: entity1Id,
|
|
243
|
+
target_module: module2,
|
|
244
|
+
target_entity_type: entity2Type,
|
|
245
|
+
target_entity_id: entity2Id,
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
source_module: module2,
|
|
249
|
+
source_entity_type: entity2Type,
|
|
250
|
+
source_entity_id: entity2Id,
|
|
251
|
+
target_module: module1,
|
|
252
|
+
target_entity_type: entity1Type,
|
|
253
|
+
target_entity_id: entity1Id,
|
|
254
|
+
},
|
|
255
|
+
]
|
|
256
|
+
: [
|
|
257
|
+
{
|
|
258
|
+
sourceModule: module1,
|
|
259
|
+
sourceEntityType: entity1Type,
|
|
260
|
+
sourceEntityId: entity1Id,
|
|
261
|
+
targetModule: module2,
|
|
262
|
+
targetEntityType: entity2Type,
|
|
263
|
+
targetEntityId: entity2Id,
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
sourceModule: module2,
|
|
267
|
+
sourceEntityType: entity2Type,
|
|
268
|
+
sourceEntityId: entity2Id,
|
|
269
|
+
targetModule: module1,
|
|
270
|
+
targetEntityType: entity1Type,
|
|
271
|
+
targetEntityId: entity1Id,
|
|
272
|
+
},
|
|
273
|
+
],
|
|
140
274
|
},
|
|
141
275
|
});
|
|
142
276
|
|
|
143
|
-
return
|
|
277
|
+
return record ? this.toDomainLink(record as IntegrationLinkRecord) : null;
|
|
144
278
|
}
|
|
145
279
|
|
|
146
280
|
/**
|
|
147
281
|
* Count links from a module
|
|
148
282
|
*/
|
|
149
283
|
async countFromModule(sourceModule: string): Promise<number> {
|
|
150
|
-
|
|
151
|
-
|
|
284
|
+
const { delegate, useSnakeCase } = this.resolvePersistence();
|
|
285
|
+
return delegate.count({
|
|
286
|
+
where: useSnakeCase ? { source_module: sourceModule } : { sourceModule },
|
|
152
287
|
});
|
|
153
288
|
}
|
|
154
289
|
}
|