@comake/skl-js-engine 1.3.13 → 1.3.15
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/SklEngine.d.ts +9 -6
- package/dist/SklEngine.d.ts.map +1 -1
- package/dist/SklEngine.js +37 -20
- package/dist/SklEngine.js.map +1 -1
- package/dist/hooks/globalHooks.d.ts +6 -6
- package/dist/hooks/globalHooks.d.ts.map +1 -1
- package/dist/hooks/globalHooks.js +19 -12
- package/dist/hooks/globalHooks.js.map +1 -1
- package/dist/hooks/types.d.ts +3 -1
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/hooks/types.js.map +1 -1
- package/dist/storage/query-adapter/sparql/SparqlUpdateBuilder.d.ts +1 -0
- package/dist/storage/query-adapter/sparql/SparqlUpdateBuilder.d.ts.map +1 -1
- package/dist/storage/query-adapter/sparql/SparqlUpdateBuilder.js +65 -32
- package/dist/storage/query-adapter/sparql/SparqlUpdateBuilder.js.map +1 -1
- package/package.json +1 -1
- package/src/SklEngine.ts +45 -26
- package/src/hooks/globalHooks.ts +29 -12
- package/src/hooks/types.ts +3 -1
- package/src/storage/query-adapter/sparql/SparqlUpdateBuilder.ts +79 -43
package/src/SklEngine.ts
CHANGED
|
@@ -81,6 +81,8 @@ export type CapabilityInterface = Record<string, CapabilityHandler>;
|
|
|
81
81
|
|
|
82
82
|
export type MappingResponseOption<T extends boolean> = T extends true ? JSONObject : NodeObject;
|
|
83
83
|
|
|
84
|
+
export type WriteOptions = { bypassHooks?: boolean };
|
|
85
|
+
|
|
84
86
|
export class SKLEngine implements SKLEngineInterface {
|
|
85
87
|
private readonly queryAdapter: QueryAdapter;
|
|
86
88
|
private readonly functions?: Record<string, (args: any | any[]) => any>;
|
|
@@ -149,7 +151,8 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
149
151
|
const context = {
|
|
150
152
|
entities: [],
|
|
151
153
|
operation: 'find',
|
|
152
|
-
operationParameters: { options }
|
|
154
|
+
operationParameters: { options },
|
|
155
|
+
sklEngine: this
|
|
153
156
|
};
|
|
154
157
|
|
|
155
158
|
await globalHooks.execute(HookTypes.READ, HookStages.BEFORE, context);
|
|
@@ -176,7 +179,8 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
176
179
|
const context = {
|
|
177
180
|
entities: [],
|
|
178
181
|
operation: 'findBy',
|
|
179
|
-
operationParameters: { where }
|
|
182
|
+
operationParameters: { where },
|
|
183
|
+
sklEngine: this
|
|
180
184
|
};
|
|
181
185
|
await globalHooks.execute(HookTypes.READ, HookStages.BEFORE, context);
|
|
182
186
|
try {
|
|
@@ -208,7 +212,8 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
208
212
|
const context = {
|
|
209
213
|
entities: [],
|
|
210
214
|
operation: 'findAll',
|
|
211
|
-
operationParameters: { options }
|
|
215
|
+
operationParameters: { options },
|
|
216
|
+
sklEngine: this
|
|
212
217
|
};
|
|
213
218
|
await globalHooks.execute(HookTypes.READ, HookStages.BEFORE, context);
|
|
214
219
|
try {
|
|
@@ -228,7 +233,8 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
228
233
|
const context = {
|
|
229
234
|
entities: [],
|
|
230
235
|
operation: 'groupBy',
|
|
231
|
-
operationParameters: { options }
|
|
236
|
+
operationParameters: { options },
|
|
237
|
+
sklEngine: this
|
|
232
238
|
};
|
|
233
239
|
await globalHooks.execute(HookTypes.READ, HookStages.BEFORE, context);
|
|
234
240
|
try {
|
|
@@ -248,7 +254,8 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
248
254
|
const context = {
|
|
249
255
|
entities: [],
|
|
250
256
|
operation: 'findAllBy',
|
|
251
|
-
operationParameters: { where }
|
|
257
|
+
operationParameters: { where },
|
|
258
|
+
sklEngine: this
|
|
252
259
|
};
|
|
253
260
|
await globalHooks.execute(HookTypes.READ, HookStages.BEFORE, context);
|
|
254
261
|
try {
|
|
@@ -271,30 +278,30 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
271
278
|
return PerformanceLogger.withSpanRoot('SklEngine.count', async() => this.queryAdapter.count(options), { options });
|
|
272
279
|
}
|
|
273
280
|
|
|
274
|
-
public async save(entity: Entity): Promise<Entity>;
|
|
275
|
-
public async save(entities: Entity[]): Promise<Entity[]>;
|
|
276
|
-
public async save(entityOrEntities: Entity | Entity[]): Promise<Entity | Entity[]> {
|
|
281
|
+
public async save(entity: Entity, options?: WriteOptions): Promise<Entity>;
|
|
282
|
+
public async save(entities: Entity[], options?: WriteOptions): Promise<Entity[]>;
|
|
283
|
+
public async save(entityOrEntities: Entity | Entity[], options?: WriteOptions): Promise<Entity | Entity[]> {
|
|
277
284
|
return PerformanceLogger.withSpanRoot('SklEngine.save', async() => {
|
|
278
285
|
const entityArray = Array.isArray(entityOrEntities) ? entityOrEntities : [entityOrEntities];
|
|
279
286
|
const isSingleEntity = !Array.isArray(entityOrEntities);
|
|
280
287
|
|
|
281
|
-
await globalHooks.executeBeforeCreate(entityArray);
|
|
288
|
+
await globalHooks.executeBeforeCreate(entityArray, { sklEngine: this, bypassHooks: options?.bypassHooks });
|
|
282
289
|
|
|
283
290
|
try {
|
|
284
291
|
await this.validateEntitiesConformToObjectSchema(entityArray);
|
|
285
292
|
const savedEntities = await this.queryAdapter.save(entityArray);
|
|
286
|
-
await globalHooks.executeAfterCreate(savedEntities);
|
|
293
|
+
await globalHooks.executeAfterCreate(savedEntities, { sklEngine: this, bypassHooks: options?.bypassHooks });
|
|
287
294
|
return isSingleEntity ? savedEntities[0] : savedEntities;
|
|
288
295
|
} catch (error) {
|
|
289
|
-
await globalHooks.executeErrorCreate(entityArray, error as Error);
|
|
296
|
+
await globalHooks.executeErrorCreate(entityArray, error as Error, { sklEngine: this, bypassHooks: options?.bypassHooks });
|
|
290
297
|
throw error;
|
|
291
298
|
}
|
|
292
299
|
}, { entityCount: Array.isArray(entityOrEntities) ? entityOrEntities.length : 1 });
|
|
293
300
|
}
|
|
294
301
|
|
|
295
|
-
public async update(id: string, attributes: Partial<Entity
|
|
296
|
-
public async update(ids: string[], attributes: Partial<Entity
|
|
297
|
-
public async update(idOrIds: string | string[], attributes: Partial<Entity
|
|
302
|
+
public async update(id: string, attributes: Partial<Entity>, options?: WriteOptions): Promise<void>;
|
|
303
|
+
public async update(ids: string[], attributes: Partial<Entity>, options?: WriteOptions): Promise<void>;
|
|
304
|
+
public async update(idOrIds: string | string[], attributes: Partial<Entity>, options?: WriteOptions): Promise<void> {
|
|
298
305
|
return PerformanceLogger.withSpanRoot('SklEngine.update', async() => {
|
|
299
306
|
const idArray = Array.isArray(idOrIds) ? idOrIds : [idOrIds];
|
|
300
307
|
const isSingleEntity = !Array.isArray(idOrIds);
|
|
@@ -302,7 +309,9 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
302
309
|
await globalHooks.execute(HookTypes.UPDATE, HookStages.BEFORE, {
|
|
303
310
|
entities: [],
|
|
304
311
|
operation: 'update',
|
|
305
|
-
operationParameters: { idArray, attributes }
|
|
312
|
+
operationParameters: { idArray, attributes },
|
|
313
|
+
sklEngine: this,
|
|
314
|
+
bypassHooks: options?.bypassHooks
|
|
306
315
|
});
|
|
307
316
|
|
|
308
317
|
try {
|
|
@@ -316,13 +325,17 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
316
325
|
await globalHooks.execute(HookTypes.UPDATE, HookStages.AFTER, {
|
|
317
326
|
entities: [],
|
|
318
327
|
operation: 'update',
|
|
319
|
-
operationParameters: { idArray, attributes }
|
|
328
|
+
operationParameters: { idArray, attributes },
|
|
329
|
+
sklEngine: this,
|
|
330
|
+
bypassHooks: options?.bypassHooks
|
|
320
331
|
});
|
|
321
332
|
} catch (error: unknown) {
|
|
322
333
|
await globalHooks.execute(HookTypes.UPDATE, HookStages.ERROR, {
|
|
323
334
|
entities: [],
|
|
324
335
|
operation: 'update',
|
|
325
|
-
operationParameters: { idArray, attributes }
|
|
336
|
+
operationParameters: { idArray, attributes },
|
|
337
|
+
sklEngine: this,
|
|
338
|
+
bypassHooks: options?.bypassHooks
|
|
326
339
|
}, error);
|
|
327
340
|
throw error;
|
|
328
341
|
}
|
|
@@ -470,16 +483,18 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
470
483
|
}
|
|
471
484
|
}
|
|
472
485
|
|
|
473
|
-
public async delete(id: string): Promise<void>;
|
|
474
|
-
public async delete(ids: string[]): Promise<void>;
|
|
475
|
-
public async delete(idOrIds: string | string[]): Promise<void> {
|
|
486
|
+
public async delete(id: string, options?: WriteOptions): Promise<void>;
|
|
487
|
+
public async delete(ids: string[], options?: WriteOptions): Promise<void>;
|
|
488
|
+
public async delete(idOrIds: string | string[], options?: WriteOptions): Promise<void> {
|
|
476
489
|
return PerformanceLogger.withSpanRoot('SklEngine.delete', async() => {
|
|
477
490
|
const idArray = Array.isArray(idOrIds) ? idOrIds : [idOrIds];
|
|
478
491
|
|
|
479
492
|
await globalHooks.execute(HookTypes.DELETE, HookStages.BEFORE, {
|
|
480
493
|
entities: [],
|
|
481
494
|
operation: 'delete',
|
|
482
|
-
operationParameters: { idArray }
|
|
495
|
+
operationParameters: { idArray },
|
|
496
|
+
sklEngine: this,
|
|
497
|
+
bypassHooks: options?.bypassHooks
|
|
483
498
|
});
|
|
484
499
|
|
|
485
500
|
try {
|
|
@@ -488,13 +503,17 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
488
503
|
await globalHooks.execute(HookTypes.DELETE, HookStages.AFTER, {
|
|
489
504
|
entities: [],
|
|
490
505
|
operation: 'delete',
|
|
491
|
-
operationParameters: { idArray }
|
|
506
|
+
operationParameters: { idArray },
|
|
507
|
+
sklEngine: this,
|
|
508
|
+
bypassHooks: options?.bypassHooks
|
|
492
509
|
});
|
|
493
510
|
} catch (error) {
|
|
494
511
|
await globalHooks.execute(HookTypes.DELETE, HookStages.ERROR, {
|
|
495
512
|
entities: [],
|
|
496
513
|
operation: 'delete',
|
|
497
|
-
operationParameters: { idArray }
|
|
514
|
+
operationParameters: { idArray },
|
|
515
|
+
sklEngine: this,
|
|
516
|
+
bypassHooks: options?.bypassHooks
|
|
498
517
|
}, error);
|
|
499
518
|
throw error;
|
|
500
519
|
}
|
|
@@ -609,7 +628,7 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
609
628
|
// Execute capability mapping before hook if appropriate -
|
|
610
629
|
// works for any mapping that can be used as a verb mapping
|
|
611
630
|
if (mapping) {
|
|
612
|
-
await globalHooks.executeBeforeExecuteCapabilityMapping([capabilityArgs] as Entity[], mapping);
|
|
631
|
+
await globalHooks.executeBeforeExecuteCapabilityMapping([capabilityArgs] as Entity[], mapping, { sklEngine: this });
|
|
613
632
|
}
|
|
614
633
|
|
|
615
634
|
const verbReturnValue = await this.executeMapping(mapping, capabilityArgs, capabilityConfig, account);
|
|
@@ -620,7 +639,7 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
620
639
|
|
|
621
640
|
// Execute capability mapping after hook if appropriate
|
|
622
641
|
if (mapping) {
|
|
623
|
-
await globalHooks.executeAfterExecuteCapabilityMapping([capabilityArgs] as Entity[], mapping, verbReturnValue);
|
|
642
|
+
await globalHooks.executeAfterExecuteCapabilityMapping([capabilityArgs] as Entity[], mapping, verbReturnValue, { sklEngine: this });
|
|
624
643
|
}
|
|
625
644
|
|
|
626
645
|
this.globalCallbacks?.onCapabilityEnd?.(capability[PROP_ENTITY_ID], verbReturnValue);
|
|
@@ -632,7 +651,7 @@ export class SKLEngine implements SKLEngineInterface {
|
|
|
632
651
|
} catch (error) {
|
|
633
652
|
// Execute capability mapping error hook if appropriate
|
|
634
653
|
if (mapping) {
|
|
635
|
-
await globalHooks.executeErrorExecuteCapabilityMapping([capabilityArgs] as Entity[], mapping, error as Error);
|
|
654
|
+
await globalHooks.executeErrorExecuteCapabilityMapping([capabilityArgs] as Entity[], mapping, error as Error, { sklEngine: this });
|
|
636
655
|
}
|
|
637
656
|
throw error;
|
|
638
657
|
}
|
package/src/hooks/globalHooks.ts
CHANGED
|
@@ -100,6 +100,10 @@ class GlobalHooksRegistry {
|
|
|
100
100
|
* Execute hooks for a specific operation and stage
|
|
101
101
|
*/
|
|
102
102
|
async execute(type: symbol, stage: symbol, context: SklHookContext, resultOrError?: any): Promise<any> {
|
|
103
|
+
// Allow bypassing hooks to prevent re-entrancy from within hooks
|
|
104
|
+
if (context?.bypassHooks) {
|
|
105
|
+
return resultOrError;
|
|
106
|
+
}
|
|
103
107
|
const hooksList = this.hooks.get(type)?.get(stage);
|
|
104
108
|
|
|
105
109
|
if (!hooksList || hooksList.length === 0) {
|
|
@@ -166,43 +170,53 @@ class GlobalHooksRegistry {
|
|
|
166
170
|
}
|
|
167
171
|
|
|
168
172
|
// Execution convenience methods
|
|
169
|
-
async executeBeforeCreate(entities: Entity[]): Promise<void> {
|
|
170
|
-
await this.execute(
|
|
173
|
+
async executeBeforeCreate(entities: Entity[], extras?: Partial<SklHookContext>): Promise<void> {
|
|
174
|
+
await this.execute(
|
|
175
|
+
HookTypes.CREATE,
|
|
176
|
+
HookStages.BEFORE,
|
|
177
|
+
{ entities, operation: 'save', operationParameters: {}, ...extras}
|
|
178
|
+
);
|
|
171
179
|
}
|
|
172
180
|
|
|
173
|
-
async executeAfterCreate(entities: Entity | Entity[]): Promise<any> {
|
|
181
|
+
async executeAfterCreate(entities: Entity | Entity[], extras?: Partial<SklHookContext>): Promise<any> {
|
|
174
182
|
if (!Array.isArray(entities)) {
|
|
175
183
|
entities = [ entities ];
|
|
176
184
|
}
|
|
177
185
|
return this.execute(
|
|
178
186
|
HookTypes.CREATE,
|
|
179
187
|
HookStages.AFTER,
|
|
180
|
-
{ entities, operation: 'save', operationParameters: {}},
|
|
188
|
+
{ entities, operation: 'save', operationParameters: {}, ...extras},
|
|
181
189
|
entities
|
|
182
190
|
);
|
|
183
191
|
}
|
|
184
192
|
|
|
185
|
-
async executeErrorCreate(entities: Entity[], error: Error): Promise<void> {
|
|
193
|
+
async executeErrorCreate(entities: Entity[], error: Error, extras?: Partial<SklHookContext>): Promise<void> {
|
|
186
194
|
await this.execute(
|
|
187
195
|
HookTypes.CREATE,
|
|
188
196
|
HookStages.ERROR,
|
|
189
|
-
{ entities, operation: 'save', operationParameters: {}},
|
|
197
|
+
{ entities, operation: 'save', operationParameters: {}, ...extras},
|
|
190
198
|
error
|
|
191
199
|
);
|
|
192
200
|
}
|
|
193
201
|
|
|
194
|
-
async executeBeforeExecuteCapabilityMapping(
|
|
202
|
+
async executeBeforeExecuteCapabilityMapping(
|
|
203
|
+
entities: Entity[],
|
|
204
|
+
capabilityMapping: CapabilityMapping,
|
|
205
|
+
extras?: Partial<SklHookContext>
|
|
206
|
+
): Promise<void> {
|
|
195
207
|
await this.execute(HookTypes.EXECUTE_CAPABILITY_MAPPING, HookStages.BEFORE, {
|
|
196
208
|
entities,
|
|
197
209
|
operation: 'executeCapabilityMapping',
|
|
198
|
-
operationParameters: { capabilityMapping }
|
|
210
|
+
operationParameters: { capabilityMapping },
|
|
211
|
+
...extras
|
|
199
212
|
});
|
|
200
213
|
}
|
|
201
214
|
|
|
202
215
|
async executeAfterExecuteCapabilityMapping(
|
|
203
216
|
entities: Entity[],
|
|
204
217
|
capabilityMapping: CapabilityMapping,
|
|
205
|
-
result: any
|
|
218
|
+
result: any,
|
|
219
|
+
extras?: Partial<SklHookContext>
|
|
206
220
|
): Promise<any> {
|
|
207
221
|
return this.execute(
|
|
208
222
|
HookTypes.EXECUTE_CAPABILITY_MAPPING,
|
|
@@ -210,7 +224,8 @@ class GlobalHooksRegistry {
|
|
|
210
224
|
{
|
|
211
225
|
entities,
|
|
212
226
|
operation: 'executeCapabilityMapping',
|
|
213
|
-
operationParameters: { capabilityMapping }
|
|
227
|
+
operationParameters: { capabilityMapping },
|
|
228
|
+
...extras
|
|
214
229
|
},
|
|
215
230
|
result
|
|
216
231
|
);
|
|
@@ -219,7 +234,8 @@ class GlobalHooksRegistry {
|
|
|
219
234
|
async executeErrorExecuteCapabilityMapping(
|
|
220
235
|
entities: Entity[],
|
|
221
236
|
capabilityMapping: CapabilityMapping,
|
|
222
|
-
error: Error
|
|
237
|
+
error: Error,
|
|
238
|
+
extras?: Partial<SklHookContext>
|
|
223
239
|
): Promise<void> {
|
|
224
240
|
await this.execute(
|
|
225
241
|
HookTypes.EXECUTE_CAPABILITY_MAPPING,
|
|
@@ -227,7 +243,8 @@ class GlobalHooksRegistry {
|
|
|
227
243
|
{
|
|
228
244
|
entities,
|
|
229
245
|
operation: 'executeCapabilityMapping',
|
|
230
|
-
operationParameters: { capabilityMapping }
|
|
246
|
+
operationParameters: { capabilityMapping },
|
|
247
|
+
...extras
|
|
231
248
|
},
|
|
232
249
|
error
|
|
233
250
|
);
|
package/src/hooks/types.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type { Entity } from '../util/Types';
|
|
1
|
+
import type { Entity, SKLEngineInterface } from '../util/Types';
|
|
2
2
|
|
|
3
3
|
export type SklHookContext = {
|
|
4
4
|
entities: Entity[];
|
|
5
5
|
operation: string;
|
|
6
6
|
operationParameters: Record<string, any>;
|
|
7
|
+
sklEngine?: SKLEngineInterface;
|
|
8
|
+
bypassHooks?: boolean;
|
|
7
9
|
};
|
|
@@ -43,6 +43,7 @@ export interface EntityUpdateQueries {
|
|
|
43
43
|
export interface EntityUpdateTriples {
|
|
44
44
|
entityTriples: Triple[];
|
|
45
45
|
timestampTriples: Triple[];
|
|
46
|
+
insertions: GraphQuads[];
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
export interface SparqlUpdateBuilderArgs {
|
|
@@ -106,9 +107,9 @@ export class SparqlUpdateBuilder {
|
|
|
106
107
|
return ids.flatMap((id): InsertDeleteOperation[] => {
|
|
107
108
|
const subject = DataFactory.namedNode(id);
|
|
108
109
|
const { attributesToUpdate, attributesToDelete } = this.partitionAttributes(attributes);
|
|
109
|
-
const deletionTriples = this.partialEntityToDeletionTriples(attributesToUpdate, subject);
|
|
110
|
-
const insertionTriples = this.partialEntityToTriples(subject, attributesToUpdate);
|
|
111
|
-
const deleteOnlyTriples = this.partialEntityToDeletionTriples(attributesToDelete, subject);
|
|
110
|
+
const { triples: deletionTriples, deletions: deletionDeletions } = this.partialEntityToDeletionTriples(attributesToUpdate, subject);
|
|
111
|
+
const { triples: insertionTriples, insertions: insertionInsertions } = this.partialEntityToTriples(subject, attributesToUpdate);
|
|
112
|
+
const { triples: deleteOnlyTriples } = this.partialEntityToDeletionTriples(attributesToDelete, subject);
|
|
112
113
|
|
|
113
114
|
const updates: InsertDeleteOperation[] = [];
|
|
114
115
|
|
|
@@ -126,10 +127,26 @@ export class SparqlUpdateBuilder {
|
|
|
126
127
|
} as InsertDeleteOperation);
|
|
127
128
|
}
|
|
128
129
|
|
|
130
|
+
for (const deletion of deletionDeletions) {
|
|
131
|
+
updates.push({
|
|
132
|
+
updateType: 'insertdelete',
|
|
133
|
+
delete: [ deletion ],
|
|
134
|
+
insert: [],
|
|
135
|
+
where: [
|
|
136
|
+
...deletion.triples.map(
|
|
137
|
+
(triple): Pattern => createSparqlOptional([ createSparqlBasicGraphPattern([ triple ]) ])
|
|
138
|
+
)
|
|
139
|
+
],
|
|
140
|
+
using: {
|
|
141
|
+
default: [ deletion.name ]
|
|
142
|
+
}
|
|
143
|
+
} as InsertDeleteOperation);
|
|
144
|
+
}
|
|
145
|
+
|
|
129
146
|
if (insertionTriples.length > 0) {
|
|
130
147
|
updates.push({
|
|
131
148
|
updateType: 'insert',
|
|
132
|
-
insert: [ createSparqlGraphQuads(subject, insertionTriples) ]
|
|
149
|
+
insert: [ createSparqlGraphQuads(subject, insertionTriples), ...insertionInsertions ]
|
|
133
150
|
} as InsertDeleteOperation);
|
|
134
151
|
}
|
|
135
152
|
|
|
@@ -192,9 +209,9 @@ export class SparqlUpdateBuilder {
|
|
|
192
209
|
return entities.reduce(
|
|
193
210
|
(obj: EntityUpdateQueries, entity): EntityUpdateQueries => {
|
|
194
211
|
const entityGraphName = DataFactory.namedNode(entity['@id']);
|
|
195
|
-
const { entityTriples, timestampTriples } = this.entityToTriples(entity, entityGraphName);
|
|
212
|
+
const { entityTriples, timestampTriples, insertions } = this.entityToTriples(entity, entityGraphName);
|
|
196
213
|
obj.clear.push(createSparqlClearUpdate(entityGraphName));
|
|
197
|
-
obj.insertions.push(createSparqlGraphQuads(entityGraphName, entityTriples));
|
|
214
|
+
obj.insertions.push(createSparqlGraphQuads(entityGraphName, entityTriples), ...insertions);
|
|
198
215
|
if (timestampTriples.length > 0) {
|
|
199
216
|
obj.timestampInsertions.push(createSparqlGraphQuads(entityGraphName, timestampTriples));
|
|
200
217
|
}
|
|
@@ -218,45 +235,52 @@ export class SparqlUpdateBuilder {
|
|
|
218
235
|
});
|
|
219
236
|
}
|
|
220
237
|
|
|
221
|
-
private partialEntityToDeletionTriples(entity: NodeObject, subject: NamedNode): Triple[] {
|
|
222
|
-
return Object.
|
|
238
|
+
private partialEntityToDeletionTriples(entity: NodeObject, subject: NamedNode): { triples: Triple[]; deletions: GraphQuads[] } {
|
|
239
|
+
return Object.entries(entity).reduce((acc: { triples: Triple[]; deletions: GraphQuads[] }, [ key, value ]): { triples: Triple[]; deletions: GraphQuads[] } => {
|
|
223
240
|
if (key !== '@id') {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
this.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
241
|
+
let deletions: GraphQuads[] = [];
|
|
242
|
+
if (value && typeof value === 'object' && '@id' in value && typeof value['@id'] === 'string' && '@type' in value) {
|
|
243
|
+
const { triples: nestedTriples, deletions: nestedDeletions } = this.partialEntityToDeletionTriples(value as NodeObject, DataFactory.namedNode(value['@id']));
|
|
244
|
+
deletions = [ ...deletions, createSparqlGraphQuads(DataFactory.namedNode(value['@id']), nestedTriples), ...nestedDeletions ];
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
triples: [
|
|
248
|
+
...acc.triples,
|
|
249
|
+
this.buildTriplesWithSubjectPredicateAndVariableValue(
|
|
250
|
+
subject,
|
|
251
|
+
key === '@type' ? rdfTypeNamedNode : DataFactory.namedNode(key),
|
|
252
|
+
this.variableGenerator.getNext()
|
|
253
|
+
)
|
|
254
|
+
],
|
|
255
|
+
deletions: [ ...acc.deletions, ...deletions ]
|
|
256
|
+
};
|
|
232
257
|
}
|
|
233
|
-
return
|
|
234
|
-
}, []);
|
|
258
|
+
return acc;
|
|
259
|
+
}, { triples: [], deletions: [] });
|
|
235
260
|
}
|
|
236
261
|
|
|
237
|
-
private partialEntityToTriples(subject: NamedNode, entity: NodeObject): Triple[] {
|
|
238
|
-
|
|
262
|
+
private partialEntityToTriples(subject: NamedNode, entity: NodeObject): { triples: Triple[]; insertions: GraphQuads[] } {
|
|
263
|
+
return Object.entries(entity).reduce((acc: { triples: Triple[]; insertions: GraphQuads[] }, [ key, value ]): { triples: Triple[]; insertions: GraphQuads[] } => {
|
|
239
264
|
const values = ensureArray(value);
|
|
240
265
|
if (key !== '@id') {
|
|
241
|
-
let predicateTriples: Triple[];
|
|
266
|
+
let predicateTriples: { triples: Triple[]; insertions: GraphQuads[] };
|
|
242
267
|
if (key === '@type') {
|
|
243
|
-
predicateTriples = this.buildTriplesWithSubjectPredicateAndIriValue(
|
|
268
|
+
predicateTriples = { triples: this.buildTriplesWithSubjectPredicateAndIriValue(
|
|
244
269
|
subject,
|
|
245
270
|
rdfTypeNamedNode,
|
|
246
271
|
values as string[]
|
|
247
|
-
);
|
|
272
|
+
), insertions: [] };
|
|
248
273
|
} else {
|
|
249
274
|
predicateTriples = this.buildTriplesForSubjectPredicateAndValues(subject, key, values);
|
|
250
275
|
}
|
|
251
|
-
return [ ...triples, ...predicateTriples ];
|
|
276
|
+
return { triples: [ ...acc.triples, ...predicateTriples.triples ], insertions: [ ...acc.insertions, ...predicateTriples.insertions ] };
|
|
252
277
|
}
|
|
253
|
-
return
|
|
254
|
-
}, []);
|
|
255
|
-
return entityTriples;
|
|
278
|
+
return acc;
|
|
279
|
+
}, { triples: [], insertions: [] });
|
|
256
280
|
}
|
|
257
281
|
|
|
258
282
|
private entityToTriples(entity: NodeObject, subject: BlankNode | NamedNode): EntityUpdateTriples {
|
|
259
|
-
const entityTriples = Object.entries(entity).reduce((triples: Triple[], [ key, value ]): Triple[] => {
|
|
283
|
+
const entityTriples = Object.entries(entity).reduce((acc: { triples: Triple[]; insertions: GraphQuads[] }, [ key, value ]): { triples: Triple[]; insertions: GraphQuads[] } => {
|
|
260
284
|
const values = ensureArray(value);
|
|
261
285
|
if (key !== '@id') {
|
|
262
286
|
if (key === '@type') {
|
|
@@ -265,15 +289,15 @@ export class SparqlUpdateBuilder {
|
|
|
265
289
|
rdfTypeNamedNode,
|
|
266
290
|
values as string[]
|
|
267
291
|
);
|
|
268
|
-
return [ ...triples, ...predicateTriples ];
|
|
292
|
+
return { triples: [ ...acc.triples, ...predicateTriples ], insertions: acc.insertions };
|
|
269
293
|
}
|
|
270
294
|
if (!(this.setTimestamps && key === EngineConstants.prop.dateModified)) {
|
|
271
295
|
const predicateTriples = this.buildTriplesForSubjectPredicateAndValues(subject, key, values);
|
|
272
|
-
return [ ...triples, ...predicateTriples ];
|
|
296
|
+
return { triples: [ ...acc.triples, ...predicateTriples.triples ], insertions: [ ...acc.insertions, ...predicateTriples.insertions ] };
|
|
273
297
|
}
|
|
274
298
|
}
|
|
275
|
-
return
|
|
276
|
-
}, []);
|
|
299
|
+
return acc;
|
|
300
|
+
}, { triples: [], insertions: [] });
|
|
277
301
|
|
|
278
302
|
const timestampTriples = [];
|
|
279
303
|
if (this.setTimestamps && subject.termType === 'NamedNode') {
|
|
@@ -283,7 +307,8 @@ export class SparqlUpdateBuilder {
|
|
|
283
307
|
timestampTriples.push({ subject, predicate: modified, object: now });
|
|
284
308
|
}
|
|
285
309
|
return {
|
|
286
|
-
entityTriples,
|
|
310
|
+
entityTriples: entityTriples.triples,
|
|
311
|
+
insertions: entityTriples.insertions,
|
|
287
312
|
timestampTriples
|
|
288
313
|
};
|
|
289
314
|
}
|
|
@@ -292,10 +317,14 @@ export class SparqlUpdateBuilder {
|
|
|
292
317
|
subject: BlankNode | NamedNode,
|
|
293
318
|
predicate: string,
|
|
294
319
|
values: any[]
|
|
295
|
-
): Triple[] {
|
|
320
|
+
): { triples: Triple[]; insertions: GraphQuads[] } {
|
|
296
321
|
const predicateTerm = DataFactory.namedNode(predicate);
|
|
297
|
-
|
|
298
|
-
|
|
322
|
+
// Return values.flatMap((value: any): { triples: Triple[]; insertions: GraphQuads[] } =>
|
|
323
|
+
// this.buildTriplesWithSubjectPredicateAndValue(subject, predicateTerm, value));
|
|
324
|
+
return values.reduce((acc: { triples: Triple[]; insertions: GraphQuads[] }, value: any) => {
|
|
325
|
+
const { triples, insertions } = this.buildTriplesWithSubjectPredicateAndValue(subject, predicateTerm, value);
|
|
326
|
+
return { triples: [ ...acc.triples, ...triples ], insertions: [ ...acc.insertions, ...insertions ] };
|
|
327
|
+
}, { triples: [], insertions: [] });
|
|
299
328
|
}
|
|
300
329
|
|
|
301
330
|
private buildTriplesWithSubjectPredicateAndIriValue(
|
|
@@ -329,26 +358,33 @@ export class SparqlUpdateBuilder {
|
|
|
329
358
|
subject: BlankNode | NamedNode,
|
|
330
359
|
predicate: NamedNode,
|
|
331
360
|
value: any
|
|
332
|
-
): Triple[] {
|
|
361
|
+
): { triples: Triple[]; insertions: GraphQuads[] } {
|
|
333
362
|
const isObject = typeof value === 'object';
|
|
334
363
|
if (isObject) {
|
|
335
364
|
if ('@list' in value) {
|
|
336
|
-
return this.buildTriplesForList(subject, predicate, value['@list']);
|
|
365
|
+
return { triples: this.buildTriplesForList(subject, predicate, value['@list']), insertions: [] };
|
|
337
366
|
}
|
|
338
367
|
if ('@value' in value) {
|
|
339
|
-
return [ { subject, predicate, object: this.jsonLdValueObjectToLiteral(value) } as Triple ];
|
|
368
|
+
return { triples: [ { subject, predicate, object: this.jsonLdValueObjectToLiteral(value) } as Triple ], insertions: [] };
|
|
340
369
|
}
|
|
341
370
|
|
|
342
371
|
const isReferenceObject = '@id' in value;
|
|
343
372
|
const isBlankNodeReferenceObject = !isReferenceObject || (value['@id'] as string).startsWith('_:');
|
|
344
373
|
if (isBlankNodeReferenceObject) {
|
|
345
|
-
return this.buildTriplesForBlankNode(subject, predicate, value as NodeObject);
|
|
374
|
+
return { triples: this.buildTriplesForBlankNode(subject, predicate, value as NodeObject), insertions: [] };
|
|
346
375
|
}
|
|
347
376
|
if (isReferenceObject) {
|
|
348
|
-
|
|
377
|
+
const triples = [
|
|
378
|
+
{ subject, predicate, object: DataFactory.namedNode(value['@id']) } as Triple
|
|
379
|
+
];
|
|
380
|
+
if (value['@type']) {
|
|
381
|
+
const { entityTriples, insertions } = this.entityToTriples(value as NodeObject, DataFactory.namedNode(value['@id']));
|
|
382
|
+
return { triples, insertions: [ ...insertions, createSparqlGraphQuads(DataFactory.namedNode(value['@id']), entityTriples) ] };
|
|
383
|
+
}
|
|
384
|
+
return { triples, insertions: [] };
|
|
349
385
|
}
|
|
350
386
|
}
|
|
351
|
-
return [ { subject, predicate, object: valueToLiteral(value) } as Triple ];
|
|
387
|
+
return { triples: [ { subject, predicate, object: valueToLiteral(value) } as Triple ], insertions: [] };
|
|
352
388
|
}
|
|
353
389
|
|
|
354
390
|
private jsonLdValueObjectToLiteral(value: ValueObject): Term {
|
|
@@ -372,7 +408,7 @@ export class SparqlUpdateBuilder {
|
|
|
372
408
|
: [{ subject: blankNode, predicate: restPredicate, object: nilPredicate }];
|
|
373
409
|
return [
|
|
374
410
|
{ subject, predicate, object: blankNode },
|
|
375
|
-
...this.buildTriplesWithSubjectPredicateAndValue(blankNode, firstPredicate, value[0]),
|
|
411
|
+
...this.buildTriplesWithSubjectPredicateAndValue(blankNode, firstPredicate, value[0]).triples,
|
|
376
412
|
...rest
|
|
377
413
|
];
|
|
378
414
|
}
|