OpenHPS/openhps-rdf

View on GitHub
src/mapping/DataObject.ts

Summary

Maintainability
D
2 days
Test Coverage
import {
    DataObject,
    SerializableArrayMember,
    SerializableMember,
    SerializableObject,
    RelativePosition,
    RelativeOrientation,
} from '@openhps/core';
import { xsd } from '../rdf/types';
import { RDFSerializer, Thing } from '../rdf';
import { dcterms, poso, rdfs, sosa, ogc } from '../vocab';
import { MemberDeserializerOptions, MemberSerializerOptions, RDFMetadata } from '../decorators/options';
import { DataFactory } from 'n3';

SerializableObject({
    rdf: {
        /**
         * Feature Of Interest
         *
         * The thing whose property is being estimated or calculated in the course of an Observation to arrive at a Result or whose property is being manipulated by an Actuator, or which is being sampled or transformed in an act of Sampling.
         *
         * http://www.w3.org/ns/sosa/FeatureOfInterest
         */
        type: [sosa.FeatureOfInterest, ogc.SpatialObject],
    },
})(DataObject);
SerializableMember({
    rdf: {
        identifier: true,
        serializer: (uid: string) => uid,
        deserializer: (thing: Thing) =>
            thing.value.substring(Math.max(thing.value.lastIndexOf('/'), thing.value.lastIndexOf('#')) + 1),
    },
})(DataObject.prototype, 'uid');
SerializableMember({
    rdf: {
        predicate: dcterms.created,
        datatype: xsd.dateTime,
    },
})(DataObject.prototype, 'createdTimestamp');
SerializableMember({
    rdf: {
        predicate: rdfs.label,
    },
})(DataObject.prototype, 'displayName');
SerializableMember({
    rdf: {
        predicate: poso.hasPosition,
    },
})(DataObject.prototype, 'position');
SerializableArrayMember(RelativePosition, {
    rdf: {
        identifier: false,
        predicate: undefined,
        serializer: (value: RelativePosition[], _, options?: MemberSerializerOptions) => {
            const orientations = options.thing.predicates[poso.hasOrientation] || [];
            const positions = options.thing.predicates[poso.hasPosition] || [];

            value.forEach((relPos) => {
                if (relPos instanceof RelativeOrientation) {
                    orientations.push(
                        RDFSerializer.serialize(relPos, {
                            baseUri: options.baseUri,
                        }),
                    );
                } else {
                    positions.push(
                        RDFSerializer.serialize(relPos, {
                            baseUri: options.baseUri,
                        }),
                    );
                }
            });

            options.thing.predicates[poso.hasOrientation] = orientations;
            options.thing.predicates[poso.hasPosition] = positions;
            return undefined;
        },
        deserializer: (_1, _2, options: MemberDeserializerOptions) => {
            const relativePositions: RelativePosition[] = [];
            const orientations = options.thing.predicates[poso.hasOrientation];
            if (orientations) {
                orientations.forEach((item) => {
                    const deserialized = RDFSerializer.deserialize(item as Thing);
                    if (deserialized instanceof RelativePosition) {
                        relativePositions.push(deserialized);
                    }
                });
            }
            const positions = options.thing.predicates[poso.hasPosition];
            if (positions) {
                positions.forEach((item) => {
                    const deserialized = RDFSerializer.deserialize(item as Thing);
                    if (deserialized instanceof RelativePosition) {
                        relativePositions.push(deserialized);
                    }
                });
            }
            return relativePositions;
        },
    },
})(DataObject.prototype, 'relativePositions');

/** RDF Specific Data */
Object.defineProperty(DataObject.prototype, 'rdf', {
    enumerable: false,
    configurable: false,
    writable: true,
    value: undefined,
});
Reflect.defineMetadata('design:type', Object, DataObject.prototype, 'rdf');
SerializableMember({
    name: '__rdf',
    serializer: (rdf: RDFMetadata) => {
        if (!rdf) {
            return undefined;
        }

        const serializedPredicates = rdf.predicates
            ? Object.keys(rdf.predicates)
                  .map((predicate) => {
                      return {
                          [predicate]: rdf.predicates[predicate].map((item) => {
                              if (item['toJSON'] !== undefined && typeof item['toJSON'] === 'function') {
                                  return item['toJSON']();
                              } else {
                                  return item;
                              }
                          }),
                      };
                  })
                  .reduce((a, b) => ({ ...a, ...b }))
            : undefined;
        return {
            path: rdf.path,
            uri: rdf.uri,
            predicates: serializedPredicates,
        };
    },
    deserializer: (object: any) => {
        if (!object) {
            return undefined;
        }

        /**
         *
         * @param predicates
         */
        function deserializePredicates(predicates: any) {
            return Object.keys(predicates)
                .map((predicate: any) => {
                    return {
                        [predicate]: predicates[predicate].map((item: any) => {
                            if (item.predicates === undefined) {
                                switch (item.termType) {
                                    case 'BlankNode':
                                        return DataFactory.blankNode(item.value);
                                    case 'Literal':
                                        return DataFactory.literal(
                                            item.value,
                                            item.language ?? item.datatype
                                                ? DataFactory.namedNode(item.datatype.value)
                                                : undefined,
                                        );
                                    case 'NamedNode':
                                        return DataFactory.namedNode(item.value);
                                    default:
                                        return item;
                                }
                            } else {
                                return {
                                    predicates: deserializePredicates(item.predicates),
                                    value: item.value,
                                    termType: item.termType,
                                } as Thing;
                            }
                        }),
                    };
                })
                .reduce((a, b) => ({ ...a, ...b }), {});
        }

        const deserializedPredicates = object.predicates ? deserializePredicates(object.predicates) : {};
        return {
            path: object.path,
            uri: object.uri,
            predicates: deserializedPredicates,
        } as RDFMetadata;
    },
})(DataObject.prototype, 'rdf');
SerializableMember({
    rdf: {
        predicate: ogc.sfWithin,
        serializer: (uid: string, _, options: MemberSerializerOptions) => {
            return DataFactory.namedNode(`${options.baseUri}${uid}`);
        },
        deserializer: (thing: Thing) => {
            return thing.value.substring(Math.max(thing.value.lastIndexOf('/'), thing.value.lastIndexOf('#')) + 1);
        },
    },
})(DataObject.prototype, 'parentUID');