lib6/mapping.rulesfactories.js
/**
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { valueAs } from './mapping.highlevel';
import { isNode, isPath, isRelationship, isUnboundRelationship } from './graph-types';
import { isPoint } from './spatial-types';
import { isDate, isDateTime, isDuration, isLocalDateTime, isLocalTime, isTime } from './temporal-types';
import Vector from './vector';
/**
* @property {function(rule: ?Rule)} asString Create a {@link Rule} that validates the value is a String.
*
* @property {function(rule: ?Rule & { acceptBigInt?: boolean })} asNumber Create a {@link Rule} that validates the value is a Number.
*
* @property {function(rule: ?Rule & { acceptNumber?: boolean })} AsBigInt Create a {@link Rule} that validates the value is a BigInt.
*
* @property {function(rule: ?Rule)} asNode Create a {@link Rule} that validates the value is a {@link Node}.
*
* @property {function(rule: ?Rule)} asRelationship Create a {@link Rule} that validates the value is a {@link Relationship}.
*
* @property {function(rule: ?Rule)} asPath Create a {@link Rule} that validates the value is a {@link Path}.
*
* @property {function(rule: ?Rule & { stringify?: boolean })} asDuration Create a {@link Rule} that validates the value is a {@link Duration}.
*
* @property {function(rule: ?Rule & { stringify?: boolean })} asLocalTime Create a {@link Rule} that validates the value is a {@link LocalTime}.
*
* @property {function(rule: ?Rule & { stringify?: boolean })} asLocalDateTime Create a {@link Rule} that validates the value is a {@link LocalDateTime}.
*
* @property {function(rule: ?Rule & { stringify?: boolean })} asTime Create a {@link Rule} that validates the value is a {@link Time}.
*
* @property {function(rule: ?Rule & { stringify?: boolean })} asDateTime Create a {@link Rule} that validates the value is a {@link DateTime}.
*
* @property {function(rule: ?Rule & { stringify?: boolean })} asDate Create a {@link Rule} that validates the value is a {@link Date}.
*
* @property {function(rule: ?Rule)} asPoint Create a {@link Rule} that validates the value is a {@link Point}.
*
* @property {function(rule: ?Rule & { apply?: Rule })} asList Create a {@link Rule} that validates the value is a List.
*
* @property {function(rule: ?Rule & { asTypedList: boolean })} asVector Create a {@link Rule} that validates the value is a List.
*
* @experimental Part of the Record Object Mapping preview feature
*/
export const rule = Object.freeze({
/**
* Create a {@link Rule} that validates the value is a Boolean.
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asBoolean(rule) {
return Object.assign({ validate: (value, field) => {
if (typeof value !== 'boolean') {
throw new TypeError(`${field} should be a boolean but received ${typeof value}`);
}
} }, rule);
},
/**
* Create a {@link Rule} that validates the value is a String.
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asString(rule) {
return Object.assign({ validate: (value, field) => {
if (typeof value !== 'string') {
throw new TypeError(`${field} should be a string but received ${typeof value}`);
}
} }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link Number}.
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule & { acceptBigInt?: boolean }} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asNumber(rule) {
return Object.assign({ validate: (value, field) => {
if (typeof value === 'object' && value.low !== undefined && value.high !== undefined && Object.keys(value).length === 2) {
throw new TypeError('Number returned as Object. To use asNumber mapping, set disableLosslessIntegers or useBigInt in driver config object');
}
if (typeof value !== 'number' && ((rule === null || rule === void 0 ? void 0 : rule.acceptBigInt) !== true || typeof value !== 'bigint')) {
throw new TypeError(`${field} should be a number but received ${typeof value}`);
}
}, convert: (value) => {
if (typeof value === 'bigint') {
return Number(value);
}
return value;
} }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link BigInt}.
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule & { acceptNumber?: boolean }} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asBigInt(rule) {
return Object.assign({ validate: (value, field) => {
if (typeof value !== 'bigint' && ((rule === null || rule === void 0 ? void 0 : rule.acceptNumber) !== true || typeof value !== 'number')) {
throw new TypeError(`${field} should be a bigint but received ${typeof value}`);
}
}, convert: (value) => {
if (typeof value === 'number') {
return BigInt(value);
}
return value;
} }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link Node}.
*
* @example
* const actingJobsRules: Rules = {
* // Converts the person node to a Person object in accordance with provided rules
* person: neo4j.rule.asNode({
* convert: (node: Node) => node.as(Person, personRules)
* }),
* // Returns the movie node as a Node
* movie: neo4j.rule.asNode({}),
* }
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asNode(rule) {
return Object.assign({ validate: (value, field) => {
if (!isNode(value)) {
throw new TypeError(`${field} should be a Node but received ${typeof value}`);
}
} }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link Relationship}.
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule.
* @returns {Rule} A new rule for the value
*/
asRelationship(rule) {
return Object.assign({ validate: (value, field) => {
if (!isRelationship(value)) {
throw new TypeError(`${field} should be a Relationship but received ${typeof value}`);
}
} }, rule);
},
/**
* Create a {@link Rule} that validates the value is an {@link UnboundRelationship}
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asUnboundRelationship(rule) {
return Object.assign({ validate: (value, field) => {
if (!isUnboundRelationship(value)) {
throw new TypeError(`${field} should be a UnboundRelationship but received ${typeof value}`);
}
} }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link Path}
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asPath(rule) {
return Object.assign({ validate: (value, field) => {
if (!isPath(value)) {
throw new TypeError(`${field} should be a Path but received ${typeof value}`);
}
} }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link Point}
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asPoint(rule) {
return Object.assign({ validate: (value, field) => {
if (!isPoint(value)) {
throw new TypeError(`${field} should be a Point but received ${typeof value}`);
}
} }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link Duration}
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asDuration(rule) {
return Object.assign({ validate: (value, field) => {
if (!isDuration(value)) {
throw new TypeError(`${field} should be a Duration but received ${typeof value}`);
}
}, convert: (value) => (rule === null || rule === void 0 ? void 0 : rule.stringify) === true ? value.toString() : value }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link LocalTime}
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asLocalTime(rule) {
return Object.assign({ validate: (value, field) => {
if (!isLocalTime(value)) {
throw new TypeError(`${field} should be a LocalTime but received ${typeof value}`);
}
}, convert: (value) => (rule === null || rule === void 0 ? void 0 : rule.stringify) === true ? value.toString() : value }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link Time}
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asTime(rule) {
return Object.assign({ validate: (value, field) => {
if (!isTime(value)) {
throw new TypeError(`${field} should be a Time but received ${typeof value}`);
}
}, convert: (value) => (rule === null || rule === void 0 ? void 0 : rule.stringify) === true ? value.toString() : value }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link Date}
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asDate(rule) {
return Object.assign({ validate: (value, field) => {
if (!isDate(value)) {
throw new TypeError(`${field} should be a Date but received ${typeof value}`);
}
}, convert: (value) => convertStdDate(value, rule) }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link LocalDateTime}
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asLocalDateTime(rule) {
return Object.assign({ validate: (value, field) => {
if (!isLocalDateTime(value)) {
throw new TypeError(`${field} should be a LocalDateTime but received ${typeof value}`);
}
}, convert: (value) => convertStdDate(value, rule) }, rule);
},
/**
* Create a {@link Rule} that validates the value is a {@link DateTime}
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asDateTime(rule) {
return Object.assign({ validate: (value, field) => {
if (!isDateTime(value)) {
throw new TypeError(`${field} should be a DateTime but received ${typeof value}`);
}
}, convert: (value) => convertStdDate(value, rule) }, rule);
},
/**
* Create a {@link Rule} that validates the value is a List. Optionally taking a rule for hydrating the contained values.
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule & { apply?: Rule }} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asList(rule) {
return Object.assign({ validate: (value, field) => {
if (!Array.isArray(value)) {
throw new TypeError(`${field} should be a list but received ${typeof value}`);
}
}, convert: (list, field) => {
if ((rule === null || rule === void 0 ? void 0 : rule.apply) != null) {
return list.map((value, index) => valueAs(value, `${field}[${index}]`, rule.apply));
}
return list;
} }, rule);
},
/**
* Create a {@link Rule} that validates the value is a Vector.
*
* @experimental Part of the Record Object Mapping preview feature
* @param {Rule & { asTypedList?: boolean }} rule Configurations for the rule
* @returns {Rule} A new rule for the value
*/
asVector(rule) {
return Object.assign({ validate: (value, field) => {
if (!(value instanceof Vector)) {
throw new TypeError(`${field} should be a vector but received ${typeof value}`);
}
}, convert: (value) => {
if ((rule === null || rule === void 0 ? void 0 : rule.asTypedList) === true) {
return value._typedArray;
}
return value;
} }, rule);
}
});
function convertStdDate(value, rule) {
if (rule != null) {
if (rule.stringify === true) {
return value.toString();
}
else if (rule.toStandardDate === true) {
return value.toStandardDate();
}
}
return value;
}