Skip to content

Commit

Permalink
Merge pull request #38 from comake/feat/composite-mappings
Browse files Browse the repository at this point in the history
feat/composite-mappings
  • Loading branch information
adlerfaulkner authored Dec 4, 2023
2 parents 3290770 + 50e68dd commit d35b763
Show file tree
Hide file tree
Showing 27 changed files with 649 additions and 539 deletions.
362 changes: 183 additions & 179 deletions src/SklEngine.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './mapping/Mapper';

// Storage/Operator
export * from './storage/operator/Equal';
export * from './storage/operator/Exists';
export * from './storage/operator/GreaterThan';
export * from './storage/operator/GreaterThanOrEqual';
export * from './storage/operator/In';
Expand Down
6 changes: 3 additions & 3 deletions src/mapping/Mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as RmlParser from '@comake/rmlmapper-js';
import type { NodeObject } from 'jsonld';
import jsonld from 'jsonld';
import type { OrArray, JSONObject } from '../util/Types';
import type { OrArray, JSONValue } from '../util/Types';

export interface MapperArgs {
functions?: Record<string, (args: any | any[]) => any>;
Expand All @@ -16,15 +16,15 @@ export class Mapper {
}

public async apply(
data: JSONObject,
data: JSONValue,
mapping: OrArray<NodeObject>,
frame: Record<string, any>,
): Promise<NodeObject> {
const result = await this.doMapping(data, mapping);
return await this.frame(result, frame);
}

private async doMapping(data: JSONObject, mapping: OrArray<NodeObject>): Promise<NodeObject[]> {
private async doMapping(data: JSONValue, mapping: OrArray<NodeObject>): Promise<NodeObject[]> {
const sources = { 'input.json': JSON.stringify(data) };
const options = { functions: this.functions };
const mappingNodeObject = Array.isArray(mapping)
Expand Down
5 changes: 3 additions & 2 deletions src/storage/FindOperator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export type FindOperatorType =
| 'in'
| 'not'
| 'equal'
| 'exists'
| 'gt'
| 'gte'
| 'lt'
Expand All @@ -16,13 +17,13 @@ export type FindOperatorType =

export interface FindOperatorArgs<T, TType> {
operator: TType;
value: T | FindOperator<T, any>;
value?: T | FindOperator<T, any>;
}

export class FindOperator<T, TType extends FindOperatorType> {
public readonly type = 'operator';
public readonly operator: TType;
public readonly value: T | FindOperator<T, any>;
public readonly value?: T | FindOperator<T, any>;

public constructor(args: FindOperatorArgs<T, TType>) {
this.operator = args.operator;
Expand Down
6 changes: 6 additions & 0 deletions src/storage/operator/Exists.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { FindOperator } from '../FindOperator';

// eslint-disable-next-line @typescript-eslint/naming-convention
export function Exists(): FindOperator<undefined, 'exists'> {
return new FindOperator({ operator: 'exists' });
}
23 changes: 18 additions & 5 deletions src/storage/query-adapter/sparql/SparqlQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,15 +371,15 @@ export class SparqlQueryBuilder {
}
const variable = this.createVariable();
const triple = { subject, predicate, object: variable };
const { filter, valuePattern } = this.resolveFindOperatorAsExpressionWithMultipleValues(
const { filter, valuePattern, tripleInFilter } = this.resolveFindOperatorAsExpressionWithMultipleValues(
variable,
operator,
triple,
);
return {
values: valuePattern ? [ valuePattern ] : [],
filters: filter ? [ filter ] : [],
triples: [ triple ],
triples: tripleInFilter ? [] : [ triple ],
};
}

Expand Down Expand Up @@ -528,6 +528,14 @@ export class SparqlQueryBuilder {
tripleInFilter: true,
};
}
if (operator.operator === 'exists') {
return {
filter: createSparqlExistsOperation([
createSparqlBasicGraphPattern([ triple ]),
]),
tripleInFilter: true,
};
}
const resolvedExpression = this.resolveValueToExpression(operator.value) as Expression;
switch (operator.operator) {
case 'equal':
Expand Down Expand Up @@ -609,8 +617,13 @@ export class SparqlQueryBuilder {
triple: Triple,
): OperationExpression {
let filterExpression: FilterPattern;
const rightSideIsOperation = typeof rightSide === 'object' && 'operator' in rightSide;
if (rightSideIsOperation) {
const isFindOperator = FindOperator.isFindOperator(rightSide);
if (isFindOperator && (rightSide as FindOperator<any, any>).operator === 'exists') {
return createSparqlNotExistsOperation([
createSparqlBasicGraphPattern([ triple ]),
]);
}
if (isFindOperator) {
let expression: OperationExpression | undefined;
try {
({ filter: expression } = this.resolveFindOperatorAsExpressionWithMultipleValues(
Expand All @@ -620,7 +633,7 @@ export class SparqlQueryBuilder {
true,
));
} catch {
throw new Error(`Unsupported Not sub operator "${rightSide.operator}"`);
throw new Error(`Unsupported Not sub operator "${(rightSide as FindOperator<any, any>).operator}"`);
}
filterExpression = createSparqlFilterWithExpression(expression!);
} else {
Expand Down
78 changes: 30 additions & 48 deletions src/util/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,71 +145,53 @@ export type Verb = NodeObject & {
[SKL.parametersContext]?: ValueObject<JSONObject>;
[SKL.parameters]?: NodeShape;
[SKL.returnValue]?: NodeObject;
[SKL.returnValueFrame]?: ValueObject<JSONObject>;
[SKL.series]?: { '@list': VerbMapping[] } | (RdfList<VerbMapping> & NodeObject);
[SKL.parallel]?: NodeObject;
[SKL.returnValueMapping]?: OrArray<TriplesMap>;
};

export interface SeriesVerbArgs extends JSONObject {
originalVerbParameters: JSONObject;
previousVerbReturnValue: JSONObject;
}

export type MappingWithParameterMapping = NodeObject & {
[SKL.parameterMapping]: OrArray<TriplesMap>;
[SKL.parameterMappingFrame]: ValueObject<JSONObject>;
export type Mapping = NodeObject & {
[SKL.preProcessingMapping]?: OrArray<TriplesMap>;
[SKL.preProcessingMappingFrame]?: ValueObject<JSONObject>;
[SKL.parameterMapping]?: OrArray<TriplesMap>;
[SKL.parameterMappingFrame]?: ValueObject<JSONObject>;
[SKL.parameterReference]?: string | ValueObject<string>;
[SKL.operationId]?: ValueObject<string>;
[SKL.operationMapping]?: TriplesMap;
[SKL.verbId]?: ValueObject<string> | string;
[SKL.verbMapping]?: TriplesMap;
[SKL.returnValueMapping]?: OrArray<TriplesMap>;
[SKL.returnValueFrame]?: ValueObject<JSONObject>;
[SKL.series]?: { '@list': VerbMapping[] } | (RdfList<VerbMapping> & NodeObject);
[SKL.parallel]?: OrArray<VerbMapping>;
};

export type MappingWithParameterReference = NodeObject & {
[SKL.parameterReference]: string | ValueObject<string>;
export type VerbMapping = Mapping & {
[SKL.verb]: ReferenceNodeObject;
[SKL.noun]?: ReferenceNodeObject;
[SKL.integration]?: ReferenceNodeObject;
};

export type MappingWithReturnValueMapping = NodeObject & {
[SKL.returnValueMapping]: OrArray<TriplesMap>;
[SKL.returnValueFrame]: ValueObject<JSONObject>;
};
export type MappingWithParameterMapping = VerbMapping &
Required<Pick<VerbMapping, typeof SKL.parameterMapping | typeof SKL.parameterMappingFrame>>;

export type MappingWithVerbMapping = NodeObject & {
[SKL.verbId]?: ValueObject<string> | string;
[SKL.verbMapping]?: TriplesMap;
};
export type MappingWithParameterReference = VerbMapping &
Required<Pick<VerbMapping, typeof SKL.parameterReference>>;

export type MappingWithOperationMapping = NodeObject & {
[SKL.constantOperationId]: ValueObject<string>;
[SKL.operationMapping]?: TriplesMap;
};
export type MappingWithReturnValueMapping = VerbMapping &
Required<Pick<VerbMapping, typeof SKL.returnValueMapping | typeof SKL.returnValueFrame>>;

export interface VerbMapping extends
MappingWithVerbMapping,
Partial<MappingWithParameterMapping>,
Partial<MappingWithParameterReference>,
Partial<MappingWithReturnValueMapping> {}

export interface VerbIntegrationMapping extends
Partial<MappingWithParameterReference>,
Partial<MappingWithParameterMapping>,
MappingWithOperationMapping,
Partial<MappingWithReturnValueMapping> {
[SKL.verb]: ReferenceNodeObject;
[SKL.integration]: ReferenceNodeObject;
}
export type MappingWithSeries = VerbMapping &
Required<Pick<VerbMapping, typeof SKL.series>>;

export interface VerbNounMapping extends
Partial<MappingWithParameterReference>,
Partial<MappingWithParameterMapping>,
MappingWithVerbMapping,
Partial<MappingWithReturnValueMapping> {
[SKL.verb]: ReferenceNodeObject;
[SKL.noun]: ReferenceNodeObject;
}
export type MappingWithParallel = VerbMapping &
Required<Pick<VerbMapping, typeof SKL.parallel>>;

export interface TriggerVerbMapping extends
MappingWithVerbMapping,
Partial<MappingWithParameterReference>,
Partial<MappingWithParameterMapping> {
export type TriggerMapping = Mapping & {
[SKL.integration]: ReferenceNodeObject;
}
};

export type PossibleArrayFieldValues =
| boolean
Expand Down
51 changes: 30 additions & 21 deletions test/assets/schemas/core.json
Original file line number Diff line number Diff line change
Expand Up @@ -235,14 +235,26 @@
"shacl:path": "skl:returnValue",
"shacl:name": "returnValue",
"shacl:description": "A SHACL NodeShape specifying the format and constraints that the return value of a Verb must conform to."
},
{
"shacl:maxCount": 1,
"shacl:path": "skl:returnValueFrame",
"shacl:name": "returnValueFrame",
"shacl:datatype": "rdf:JSON",
"shacl:description": "A JSON-LD Frame used to transform the JSON-LD returned by a Mapping to this Verb."
},
}
]
},
{
"@id": "https://standardknowledge.com/ontologies/core/NounMappedVerb",
"@type": ["owl:Class", "shacl:NodeShape", "skl:Noun"],
"rdfs:subClassOf": "https://standardknowledge.com/ontologies/core/Verb"
},
{
"@id": "https://standardknowledge.com/ontologies/core/OpenApiSecuritySchemeVerb",
"@type": ["owl:Class", "shacl:NodeShape", "skl:Noun"],
"rdfs:subClassOf": "https://standardknowledge.com/ontologies/core/Verb"
},
{
"@id": "https://standardknowledge.com/ontologies/core/CompositeMapping",
"@type": ["owl:Class", "shacl:NodeShape", "skl:Noun"],
"rdfs:label": "Composite Mapping",
"rdfs:subClassOf": "https://standardknowledge.com/ontologies/core/Mapping",
"shacl:closed": false,
"shacl:property": [
{
"shacl:maxCount": 1,
"shacl:path": "skl:series",
Expand Down Expand Up @@ -334,7 +346,7 @@
"shacl:maxCount": 1,
"shacl:name": "returnValueFrame",
"shacl:datatype": "rdf:JSON",
"shacl:description": "A JSON-LD Frame used to transform the JSON-LD returned by the returnValueMapping into a prefered format. This field overrides the returnValueFrame of the Verb. If not supplied, the Verb's returnValueFrame will be used instead."
"shacl:description": "A JSON-LD Frame used to transform the JSON-LD returned by the returnValueMapping into a prefered format."
},
{
"shacl:path": "skl:parallel",
Expand Down Expand Up @@ -379,16 +391,6 @@
}
]
},
{
"@id": "https://standardknowledge.com/ontologies/core/NounMappedVerb",
"@type": ["owl:Class", "shacl:NodeShape", "skl:Noun"],
"rdfs:subClassOf": "https://standardknowledge.com/ontologies/core/Verb"
},
{
"@id": "https://standardknowledge.com/ontologies/core/OpenApiSecuritySchemeVerb",
"@type": ["owl:Class", "shacl:NodeShape", "skl:Noun"],
"rdfs:subClassOf": "https://standardknowledge.com/ontologies/core/Verb"
},
{
"@id": "https://standardknowledge.com/ontologies/core/VerbIntegrationMapping",
"@type": ["owl:Class", "shacl:NodeShape", "skl:Noun"],
Expand All @@ -409,8 +411,8 @@
{
"shacl:maxCount": 1,
"shacl:datatype": "xsd:string",
"shacl:name": "constantOperationId",
"shacl:path": "https://standardknowledge.com/ontologies/core/constantOperationId"
"shacl:name": "operationId",
"shacl:path": "https://standardknowledge.com/ontologies/core/operationId"
},
{
"shacl:maxCount": 1,
Expand All @@ -423,6 +425,13 @@
"shacl:nodeKind": "shacl:IRI",
"shacl:path": "https://standardknowledge.com/ontologies/core/returnValueMapping"
},
{
"shacl:maxCount": 1,
"shacl:path": "skl:returnValueFrame",
"shacl:name": "returnValueFrame",
"shacl:datatype": "rdf:JSON",
"shacl:description": "A JSON-LD Frame used to transform the JSON-LD returned by a Mapping to this Verb."
},
{
"shacl:maxCount": 1,
"shacl:minCount": 1,
Expand Down
17 changes: 11 additions & 6 deletions test/assets/schemas/count-in-series-verb.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@
"skl:account": { "@type": "@id" },
"skl:openApiDescription": { "@type": "@json" },
"skl:parametersContext": { "@type": "@json" },
"skl:returnValueFrame": { "@type": "@json" },
"skl:noun": { "@type": "@id" },
"skl:parameterMapping": { "@type": "@id" },
"skl:parameterMappingFrame": { "@type": "@json" },
"skl:returnValueMapping": { "@type": "@id" },
"skl:operationMapping": { "@type": "@id" },
"skl:verbMapping": { "@type": "@id" },
"integration": { "@id": "skl:integration", "@type": "@id" },
Expand Down Expand Up @@ -70,7 +68,12 @@
"shacl:datatype": "rdf:JSON"
}
]
},
}
},
{
"@id": "https://example.com/countEntitiesMapping",
"@type": "https://standardknowledge.com/ontologies/core/CompositeMapping",
"verb": "https://example.com/countEntities",
"skl:series": [
{
"skl:verbId": "https://standardknowledge.com/ontologies/skl-engine/count",
Expand All @@ -82,7 +85,10 @@
"rml:referenceFormulation": "http://semweb.mmlab.be/ns/ql#JSONPath",
"rml:source": "input.json"
},
"rr:subject": "https://example.com/mappingSubject",
"rr:subjectMap": {
"@type": "rr:SubjectMap",
"rr:termType": "rr:BlankNode"
},
"rr:predicateObjectMap": [
{
"@type": "rr:PredicateObjectMap",
Expand All @@ -101,8 +107,7 @@
"@id": "https://example.com/where",
"@type": "@json"
}
},
"@id": "https://example.com/mappingSubject"
}
}
}
]
Expand Down
9 changes: 6 additions & 3 deletions test/assets/schemas/destroy-in-series-verb.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,9 @@
"skl:account": { "@type": "@id" },
"skl:openApiDescription": { "@type": "@json" },
"skl:parametersContext": { "@type": "@json" },
"skl:returnValueFrame": { "@type": "@json" },
"skl:noun": { "@type": "@id" },
"skl:parameterMapping": { "@type": "@id" },
"skl:parameterMappingFrame": { "@type": "@json" },
"skl:returnValueMapping": { "@type": "@id" },
"skl:operationMapping": { "@type": "@id" },
"skl:verbMapping": { "@type": "@id" },
"integration": { "@id": "skl:integration", "@type": "@id" },
Expand Down Expand Up @@ -70,7 +68,12 @@
"shacl:nodeKind": "shacl:IRI"
}
]
},
}
},
{
"@id": "https://example.com/destroyEntitiesMapping",
"@type": "https://standardknowledge.com/ontologies/core/CompositeMapping",
"verb": "https://example.com/destroyEntities",
"skl:series": [
{
"skl:verbId": "https://standardknowledge.com/ontologies/skl-engine/destroy",
Expand Down
1 change: 0 additions & 1 deletion test/assets/schemas/divide-function.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
"skl:account": { "@type": "@id" },
"skl:openApiDescription": { "@type": "@json" },
"skl:parametersContext": { "@type": "@json" },
"skl:returnValueFrame": { "@type": "@json" },
"skl:noun": { "@type": "@id" },
"skl:returnValueMapping": { "@type": "@id" },
"integration": { "@id": "skl:integration", "@type": "@id" },
Expand Down
Loading

0 comments on commit d35b763

Please sign in to comment.