UNPKG

@inrupt/solid-client

Version:
479 lines (476 loc) • 22.2 kB
import { deserializeBoolean, deserializeDatetime, deserializeDecimal, deserializeInteger, xmlSchemaTypes, internal_isValidUrl, asNamedNode, isNamedNode, isLiteral, isTerm } from '../datatypes.mjs'; import { internal_throwIfNotThing } from './thing.internal.mjs'; import { ValidPropertyUrlExpectedError } from './thing.mjs'; /** * Copyright 2020 Inrupt Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * Returns the URL value of the specified Property from a [[Thing]]. * If the Property is not present or its value is not of type URL, returns null. * If the Property has multiple URL values, returns one of its URL values. * * @param thing The [[Thing]] to read a URL value from. * @param property The Property whose URL value to return. * @returns A URL value for the given Property if present, or null if the Property is not present or the value is not of type URL. */ function getUrl(thing, property) { internal_throwIfNotThing(thing); const namedNodeMatcher = getNamedNodeMatcher(property); const matchingQuad = findOne(thing, namedNodeMatcher); if (matchingQuad === null) { return null; } return matchingQuad.object.value; } /** @hidden Alias of [[getUrl]] for those who prefer IRI terminology. */ const getIri = getUrl; /** * Returns the URL values of the specified Property from a [[Thing]]. * If the Property is not present, returns an empty array. * If the Property's value is not of type URL, omits that value in the array. * * @param thing The [[Thing]] to read the URL values from. * @param property The Property whose URL values to return. * @returns An array of URL values for the given Property. */ function getUrlAll(thing, property) { internal_throwIfNotThing(thing); const iriMatcher = getNamedNodeMatcher(property); const matchingQuads = findAll(thing, iriMatcher); return matchingQuads.map((quad) => quad.object.value); } /** @hidden Alias of [[getUrlAll]] for those who prefer IRI terminology. */ const getIriAll = getUrlAll; /** * Returns the boolean value of the specified Property from a [[Thing]]. * If the Property is not present or its value is not of type boolean, returns null. * If the Property has multiple boolean values, returns one of its values. * * @param thing The [[Thing]] to read a boolean value from. * @param property The Property whose boolean value to return. * @returns A boolean value for the given Property if present, or null if the Property is not present or the value is not of type boolean. */ function getBoolean(thing, property) { internal_throwIfNotThing(thing); const literalString = getLiteralOfType(thing, property, xmlSchemaTypes.boolean); if (literalString === null) { return null; } return deserializeBoolean(literalString); } /** * Returns the boolean values of the specified Property from a [[Thing]]. * If the Property is not present, returns an empty array. * If the Property's value is not of type boolean, omits that value in the array. * * @param thing The [[Thing]] to read the boolean values from. * @param property The Property whose boolean values to return. * @returns An array of boolean values for the given Property. */ function getBooleanAll(thing, property) { internal_throwIfNotThing(thing); const literalStrings = getLiteralAllOfType(thing, property, xmlSchemaTypes.boolean); return literalStrings .map(deserializeBoolean) .filter((possibleBoolean) => possibleBoolean !== null); } /** * Returns the datetime value of the specified Property from a [[Thing]]. * If the Property is not present or its value is not of type datetime, returns null. * If the Property has multiple datetime values, returns one of its values. * * @param thing The [[Thing]] to read a datetime value from. * @param property The Property whose datetime value to return. * @returns A datetime value for the given Property if present, or null if the Property is not present or the value is not of type datetime. */ function getDatetime(thing, property) { internal_throwIfNotThing(thing); const literalString = getLiteralOfType(thing, property, xmlSchemaTypes.dateTime); if (literalString === null) { return null; } return deserializeDatetime(literalString); } /** * Returns the datetime values of the specified Property from a [[Thing]]. * If the Property is not present, returns an empty array. * If the Property's value is not of type datetime, omits that value in the array. * * @param thing The [[Thing]] to read the datetime values from. * @param property The Property whose datetime values to return. * @returns An array of datetime values for the given Property. */ function getDatetimeAll(thing, property) { internal_throwIfNotThing(thing); const literalStrings = getLiteralAllOfType(thing, property, xmlSchemaTypes.dateTime); return literalStrings .map(deserializeDatetime) .filter((potentialDatetime) => potentialDatetime !== null); } /** * Returns the decimal value of the specified Property from a [[Thing]]. * If the Property is not present or its value is not of type decimal, returns null. * If the Property has multiple decimal values, returns one of its values. * * @param thing The [[Thing]] to read a decimal value from. * @param property The Property whose decimal value to return. * @returns A decimal value for the given Property if present, or null if the Property is not present or the value is not of type decimal. */ function getDecimal(thing, property) { internal_throwIfNotThing(thing); const literalString = getLiteralOfType(thing, property, xmlSchemaTypes.decimal); if (literalString === null) { return null; } return deserializeDecimal(literalString); } /** * Returns the decimal values of the specified Property from a [[Thing]]. * If the Property is not present, returns an empty array. * If the Property's value is not of type decimal, omits that value in the array. * * @param thing The [[Thing]] to read the decimal values from. * @param property The Property whose decimal values to return. * @returns An array of decimal values for the given Property. */ function getDecimalAll(thing, property) { internal_throwIfNotThing(thing); const literalStrings = getLiteralAllOfType(thing, property, xmlSchemaTypes.decimal); return literalStrings .map((literalString) => deserializeDecimal(literalString)) .filter((potentialDecimal) => potentialDecimal !== null); } /** * Returns the integer value of the specified Property from a [[Thing]]. * If the Property is not present or its value is not of type integer, returns null. * If the Property has multiple integer values, returns one of its values. * * @param thing The [[Thing]] to read an integer value from. * @param property The Property whose integer value to return. * @returns A integer value for the given Property if present, or null if the Property is not present or the value is not of type datetime. */ function getInteger(thing, property) { internal_throwIfNotThing(thing); const literalString = getLiteralOfType(thing, property, xmlSchemaTypes.integer); if (literalString === null) { return null; } return deserializeInteger(literalString); } /** * Returns the integer values of the specified Property from a [[Thing]]. * If the Property is not present, returns an empty array. * If the Property's value is not of type integer, omits that value in the array. * * @param thing The [[Thing]] to read the integer values from. * @param property The Property whose integer values to return. * @returns An array of integer values for the given Property. */ function getIntegerAll(thing, property) { internal_throwIfNotThing(thing); const literalStrings = getLiteralAllOfType(thing, property, xmlSchemaTypes.integer); return literalStrings .map((literalString) => deserializeInteger(literalString)) .filter((potentialInteger) => potentialInteger !== null); } /** * Returns the localized string value of the specified Property from a [[Thing]]. * If the Property is not present as a string in the specified locale, returns null. * If the Property has multiple string values for the specified locale, returns one of its values. * * @param thing The [[Thing]] to read a localised string value from. * @param property The Property whose localised string value to return. * @param locale The desired locale for the string value. * @returns A localised string value for the given Property if present in the specified `locale`, or null otherwise. */ function getStringWithLocale(thing, property, locale) { internal_throwIfNotThing(thing); const localeStringMatcher = getLocaleStringMatcher(property, locale); const matchingQuad = findOne(thing, localeStringMatcher); if (matchingQuad === null) { return null; } return matchingQuad.object.value; } /** * Returns the localized string values of the specified Property from a [[Thing]]. * If the Property is not present, returns an empty array. * If the Property's value is not a string of the specified locale, omits that value in the array. * * @param thing The [[Thing]] to read the localised string values from. * @param property The Property whose localised string values to return. * @param locale The desired locale for the string values. * @returns An array of localised string values for the given Property. */ function getStringWithLocaleAll(thing, property, locale) { internal_throwIfNotThing(thing); const localeStringMatcher = getLocaleStringMatcher(property, locale); const matchingQuads = findAll(thing, localeStringMatcher); return matchingQuads.map((quad) => quad.object.value); } /** * Returns all localized string values mapped by the locales for the specified property from the * specified [[Thing]] (explicitly filters out non-language string literals). * * @param thing The [[Thing]] to read the localised string values from. * @param property The Property whose localised string values to return. * @returns A Map of objects, keyed on locale with the value an array of string values (for that locale). */ function getStringByLocaleAll(thing, property) { internal_throwIfNotThing(thing); const literalMatcher = getLiteralMatcher(property); const matchingQuads = findAll(thing, literalMatcher); const result = new Map(); matchingQuads.map((quad) => { if (quad.object.datatype.value === xmlSchemaTypes.langString) { const languageTag = quad.object.language; const current = result.get(languageTag); current ? result.set(languageTag, [...current, quad.object.value]) : result.set(languageTag, [quad.object.value]); } }); return result; } /** * Returns the string value of the specified Property from a [[Thing]]. * If the Property is not present or its value is not of type string, returns null. * If the Property has multiple string values, returns one of its values. * * @param thing The [[Thing]] to read a string value from. * @param property The Property whose string value to return. * @returns A string value for the given Property if present, or null if the Property is not present or the value is not of type string. */ function getStringNoLocale(thing, property) { internal_throwIfNotThing(thing); const literalString = getLiteralOfType(thing, property, xmlSchemaTypes.string); return literalString; } /** * Returns the string values of the specified Property from a [[Thing]]. * If the Property is not present, returns an empty array. * If the Property's value is not of type string, omits that value in the array. * * @param thing The [[Thing]] to read the string values from. * @param property The Property whose string values to return. * @returns An array of string values for the given Property. */ function getStringNoLocaleAll(thing, property) { internal_throwIfNotThing(thing); const literalStrings = getLiteralAllOfType(thing, property, xmlSchemaTypes.string); return literalStrings; } /** * @param thing The [[Thing]] to read a NamedNode value from. * @param property The given Property for which you want the NamedNode value. * @returns A NamedNode value for the given Property, if present, or null otherwise. * @ignore This should not be needed due to the other get*() functions. If you do find yourself needing it, please file a feature request for your use case. * @see https://rdf.js.org/data-model-spec/#namednode-interface */ function getNamedNode(thing, property) { internal_throwIfNotThing(thing); const namedNodeMatcher = getNamedNodeMatcher(property); const matchingQuad = findOne(thing, namedNodeMatcher); if (matchingQuad === null) { return null; } return matchingQuad.object; } /** * @param thing The [[Thing]] to read the NamedNode values from. * @param property The given Property for which you want the NamedNode values. * @returns The NamedNode values for the given Property. * @ignore This should not be needed due to the other get*() functions. If you do find yourself needing it, please file a feature request for your use case. * @see https://rdf.js.org/data-model-spec/#namednode-interface */ function getNamedNodeAll(thing, property) { internal_throwIfNotThing(thing); const namedNodeMatcher = getNamedNodeMatcher(property); const matchingQuads = findAll(thing, namedNodeMatcher); return matchingQuads.map((quad) => quad.object); } /** * @param thing The [[Thing]] to read a Literal value from. * @param property The given Property for which you want the Literal value. * @returns A Literal value for the given Property, if present, or null otherwise. * @ignore This should not be needed due to the other get*() functions. If you do find yourself needing it, please file a feature request for your use case. * @see https://rdf.js.org/data-model-spec/#literal-interface */ function getLiteral(thing, property) { internal_throwIfNotThing(thing); const literalMatcher = getLiteralMatcher(property); const matchingQuad = findOne(thing, literalMatcher); if (matchingQuad === null) { return null; } return matchingQuad.object; } /** * @param thing The [[Thing]] to read the Literal values from. * @param property The given Property for which you want the Literal values. * @returns The Literal values for the given Property. * @ignore This should not be needed due to the other get*All() functions. If you do find yourself needing it, please file a feature request for your use case. * @see https://rdf.js.org/data-model-spec/#literal-interface */ function getLiteralAll(thing, property) { internal_throwIfNotThing(thing); const literalMatcher = getLiteralMatcher(property); const matchingQuads = findAll(thing, literalMatcher); return matchingQuads.map((quad) => quad.object); } /** * @param thing The [[Thing]] to read a raw RDF/JS value from. * @param property The given Property for which you want the raw value. * @returns A Term for the given Property, if present, or null otherwise. * @ignore This should not be needed due to the other get*() functions. If you do find yourself needing it, please file a feature request for your use case. * @see https://rdf.js.org/data-model-spec/ * @since 0.3.0 */ function getTerm(thing, property) { internal_throwIfNotThing(thing); const termMatcher = getTermMatcher(property); const matchingQuad = findOne(thing, termMatcher); if (matchingQuad === null) { return null; } return matchingQuad.object; } /** * @param thing The [[Thing]] to read the raw RDF/JS values from. * @param property The given Property for which you want the raw values. * @returns The Terms for the given Property. * @ignore This should not be needed due to the other get*() functions. If you do find yourself needing it, please file a feature request for your use case. * @see https://rdf.js.org/data-model-spec/ * @since 0.3.0 */ function getTermAll(thing, property) { internal_throwIfNotThing(thing); const namedNodeMatcher = getTermMatcher(property); const matchingQuads = findAll(thing, namedNodeMatcher); return matchingQuads.map((quad) => quad.object); } /** * @param thing The [[Thing]] to extract a Quad from. * @param matcher Callback function that returns a boolean indicating whether a given Quad should be included. * @returns First Quad in `thing` for which `matcher` returned true. */ function findOne(thing, matcher) { for (const quad of thing) { if (matcher(quad)) { return quad; } } return null; } /** * @param thing The [[Thing]] to extract Quads from. * @param matcher Callback function that returns a boolean indicating whether a given Quad should be included. * @returns All Quads in `thing` for which `matcher` returned true. */ function findAll(thing, matcher) { const matched = []; for (const quad of thing) { if (matcher(quad)) { matched.push(quad); } } return matched; } function getNamedNodeMatcher(property) { if (!internal_isValidUrl(property)) { throw new ValidPropertyUrlExpectedError(property); } const predicateNode = asNamedNode(property); const matcher = function matcher(quad) { return predicateNode.equals(quad.predicate) && isNamedNode(quad.object); }; return matcher; } function getLiteralMatcher(property) { if (!internal_isValidUrl(property)) { throw new ValidPropertyUrlExpectedError(property); } const predicateNode = asNamedNode(property); const matcher = function matcher(quad) { return predicateNode.equals(quad.predicate) && isLiteral(quad.object); }; return matcher; } function getTermMatcher(property) { if (!internal_isValidUrl(property)) { throw new ValidPropertyUrlExpectedError(property); } const predicateNode = asNamedNode(property); const matcher = function matcher(quad) { return predicateNode.equals(quad.predicate) && isTerm(quad.object); }; return matcher; } function getLiteralOfTypeMatcher(property, datatype) { if (!internal_isValidUrl(property)) { throw new ValidPropertyUrlExpectedError(property); } const predicateNode = asNamedNode(property); const matcher = function matcher(quad) { return (predicateNode.equals(quad.predicate) && isLiteral(quad.object) && quad.object.datatype.value === datatype); }; return matcher; } function getLocaleStringMatcher(property, locale) { if (!internal_isValidUrl(property)) { throw new ValidPropertyUrlExpectedError(property); } const predicateNode = asNamedNode(property); const matcher = function matcher(quad) { return (predicateNode.equals(quad.predicate) && isLiteral(quad.object) && quad.object.datatype.value === xmlSchemaTypes.langString && quad.object.language.toLowerCase() === locale.toLowerCase()); }; return matcher; } /** * @param thing The [Thing]] to read a Literal of the given type from. * @param property The given Property for which you want the Literal value. * @param literalType Set type of the Literal data. * @returns The stringified value for the given Property and type, if present, or null otherwise. */ function getLiteralOfType(thing, property, literalType) { const literalOfTypeMatcher = getLiteralOfTypeMatcher(property, literalType); const matchingQuad = findOne(thing, literalOfTypeMatcher); if (matchingQuad === null) { return null; } return matchingQuad.object.value; } /** * @param thing The [Thing]] to read the Literals of the given type from. * @param property The given Property for which you want the Literal values. * @param literalType Set type of the Literal data. * @returns The stringified values for the given Property and type. */ function getLiteralAllOfType(thing, property, literalType) { const literalOfTypeMatcher = getLiteralOfTypeMatcher(property, literalType); const matchingQuads = findAll(thing, literalOfTypeMatcher); return matchingQuads.map((quad) => quad.object.value); } export { getBoolean, getBooleanAll, getDatetime, getDatetimeAll, getDecimal, getDecimalAll, getInteger, getIntegerAll, getIri, getIriAll, getLiteral, getLiteralAll, getNamedNode, getNamedNodeAll, getStringByLocaleAll, getStringNoLocale, getStringNoLocaleAll, getStringWithLocale, getStringWithLocaleAll, getTerm, getTermAll, getUrl, getUrlAll };