-
-
Notifications
You must be signed in to change notification settings - Fork 76
/
generalEvaluation.ts
130 lines (120 loc) 路 4.62 KB
/
generalEvaluation.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import { BindingsFactory } from '@comunica/bindings-factory';
import type * as RDF from '@rdfjs/types';
import { termToString } from 'rdf-string';
import type { Algebra as Alg } from 'sparqlalgebrajs';
import { translate } from 'sparqlalgebrajs';
import { AsyncEvaluator, SyncEvaluator } from '../../lib';
import type { IAsyncEvaluatorContext, AsyncExtensionFunctionCreator } from '../../lib/evaluators/AsyncEvaluator';
import type { ISyncEvaluatorContext, SyncExtensionFunctionCreator } from '../../lib/evaluators/SyncEvaluator';
const BF = new BindingsFactory();
export type GeneralEvaluationConfig = { type: 'sync'; config: ISyncEvaluatorContext } |
{ type: 'async'; config: IAsyncEvaluatorContext };
export interface IGeneralEvaluationArg {
bindings?: RDF.Bindings;
expression: string;
generalEvaluationConfig?: GeneralEvaluationConfig;
/**
* Boolean pointing out if the result of async and sync evaluation should be the same.
* Default: Check / true
*/
expectEquality?: boolean;
}
export async function generalEvaluate(arg: IGeneralEvaluationArg):
Promise<{ asyncResult: RDF.Term; syncResult?: RDF.Term }> {
const bindings: RDF.Bindings = arg.bindings ? arg.bindings : BF.bindings();
if (arg.generalEvaluationConfig?.type === 'async') {
const asyncResult = await evaluateAsync(arg.expression, bindings, arg.generalEvaluationConfig.config);
return { asyncResult };
}
const syncConfig = arg.generalEvaluationConfig?.config;
const convertedConfig = syncConfigToAsyncConfig(syncConfig);
const asyncResult = await evaluateAsync(
arg.expression,
bindings,
convertedConfig,
);
const syncResult = evaluateSync(arg.expression, bindings, syncConfig);
if (arg.expectEquality ?? arg.expectEquality === undefined) {
expect(termToString(asyncResult)).toEqual(termToString(syncResult));
}
return { asyncResult, syncResult };
}
export async function generalErrorEvaluation(arg: IGeneralEvaluationArg):
Promise<{ asyncError: unknown; syncError?: unknown } | undefined > {
const bindings: RDF.Bindings = arg.bindings ? arg.bindings : BF.bindings();
if (arg.generalEvaluationConfig?.type === 'async') {
try {
await evaluateAsync(arg.expression, bindings, arg.generalEvaluationConfig.config);
return undefined;
} catch (error: unknown) {
return { asyncError: error };
}
}
const res: { asyncError: unknown; syncError?: unknown } = Object.create(null);
const syncConfig = arg.generalEvaluationConfig?.config;
try {
await evaluateAsync(
arg.expression,
bindings,
syncConfigToAsyncConfig(syncConfig),
);
return undefined;
} catch (error: unknown) {
res.asyncError = error;
}
try {
evaluateSync(arg.expression, bindings, syncConfig);
return undefined;
} catch (error: unknown) {
res.syncError = error;
}
if (arg.expectEquality ?? arg.expectEquality === undefined) {
expect(res.asyncError).toEqual(res.syncError);
}
return res;
}
function syncConfigToAsyncConfig(config: ISyncEvaluatorContext | undefined): IAsyncEvaluatorContext | undefined {
if (!config) {
return undefined;
}
const asyncExists = config.exists ?
async(e: Alg.ExistenceExpression, m: RDF.Bindings) => config.exists!(e, m) :
undefined;
const asyncAggregate = config.aggregate ?
async(expression: Alg.AggregateExpression) => config.aggregate!(expression) :
undefined;
const asyncBnode = config.bnode ? async(input?: string) => config.bnode!(input) : undefined;
const asyncExtensionFunctionCreator = syncCallbackWrapper(config.extensionFunctionCreator);
return {
...config,
exists: asyncExists,
aggregate: asyncAggregate,
bnode: asyncBnode,
extensionFunctionCreator: asyncExtensionFunctionCreator,
};
}
function syncCallbackWrapper(f: SyncExtensionFunctionCreator | undefined): AsyncExtensionFunctionCreator | undefined {
if (!f) {
return undefined;
}
return (namedNode: RDF.NamedNode) => {
const func = f(namedNode);
if (!func) {
return;
}
return (args: RDF.Term[]) => Promise.resolve(func(args));
};
}
function parse(query: string) {
const sparqlQuery = translate(query, { sparqlStar: true });
// Extract filter expression from complete query
return sparqlQuery.input.expression;
}
function evaluateAsync(expr: string, bindings: RDF.Bindings, config?: IAsyncEvaluatorContext): Promise<RDF.Term> {
const evaluator = new AsyncEvaluator(parse(expr), config);
return evaluator.evaluate(bindings);
}
function evaluateSync(expr: string, bindings: RDF.Bindings, config?: ISyncEvaluatorContext): RDF.Term {
const evaluator = new SyncEvaluator(parse(expr), config);
return evaluator.evaluate(bindings);
}