diff --git a/src/v1/internal/util.js b/src/v1/internal/util.js
index 640d544d8..437be20be 100644
--- a/src/v1/internal/util.js
+++ b/src/v1/internal/util.js
@@ -17,6 +17,8 @@
* limitations under the License.
*/
+import {isInt} from '../integer';
+
const ENCRYPTION_ON = "ENCRYPTION_ON";
const ENCRYPTION_OFF = "ENCRYPTION_OFF";
@@ -71,6 +73,20 @@ function assertString(obj, objName) {
return obj;
}
+function assertNumber(obj, objName) {
+ if (typeof obj !== 'number') {
+ throw new TypeError(objName + ' expected to be a number but was: ' + JSON.stringify(obj));
+ }
+ return obj;
+}
+
+function assertNumberOrInteger(obj, objName) {
+ if (typeof obj !== 'number' && !isInt(obj)) {
+ throw new TypeError(objName + ' expected to be either a number or an Integer object but was: ' + JSON.stringify(obj));
+ }
+ return obj;
+}
+
function assertCypherStatement(obj) {
assertString(obj, 'Cypher statement');
if (obj.trim().length === 0) {
@@ -94,6 +110,8 @@ export {
isEmptyObjectOrNull,
isString,
assertString,
+ assertNumber,
+ assertNumberOrInteger,
validateStatementAndParameters,
ENCRYPTION_ON,
ENCRYPTION_OFF
diff --git a/src/v1/spatial-types.js b/src/v1/spatial-types.js
index ca7efc0c7..9140a00ff 100644
--- a/src/v1/spatial-types.js
+++ b/src/v1/spatial-types.js
@@ -16,6 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import {assertNumber, assertNumberOrInteger} from './internal/util';
const POINT_IDENTIFIER_PROPERTY = '__isPoint__';
@@ -33,10 +34,10 @@ export class Point {
* @param {number} [z=undefined] the y
coordinate of the point or undefined
if point has 2 dimensions.
*/
constructor(srid, x, y, z) {
- this.srid = srid;
- this.x = x;
- this.y = y;
- this.z = z;
+ this.srid = assertNumberOrInteger(srid, 'SRID');
+ this.x = assertNumber(x, 'X coordinate');
+ this.y = assertNumber(y, 'Y coordinate');
+ this.z = (z === null || z === undefined) ? z : assertNumber(z, 'Z coordinate');
Object.freeze(this);
}
diff --git a/src/v1/temporal-types.js b/src/v1/temporal-types.js
index 0cb4a9ea7..0ca11b7df 100644
--- a/src/v1/temporal-types.js
+++ b/src/v1/temporal-types.js
@@ -18,6 +18,7 @@
*/
import * as util from './internal/temporal-util';
+import {assertNumberOrInteger, assertString} from './internal/util';
import {newError} from './error';
const IDENTIFIER_PROPERTY_ATTRIBUTES = {
@@ -47,8 +48,10 @@ export class Duration {
* @param {Integer|number} nanoseconds the number of nanoseconds for the new duration.
*/
constructor(months, days, seconds, nanoseconds) {
- this.months = months;
- this.days = days;
+ this.months = assertNumberOrInteger(months, 'Months');
+ this.days = assertNumberOrInteger(days, 'Days');
+ assertNumberOrInteger(seconds, 'Seconds');
+ assertNumberOrInteger(nanoseconds, 'Nanoseconds');
this.seconds = util.normalizeSecondsForDuration(seconds, nanoseconds);
this.nanoseconds = util.normalizeNanosecondsForDuration(nanoseconds);
Object.freeze(this);
@@ -84,10 +87,10 @@ export class LocalTime {
* @param {Integer|number} nanosecond the nanosecond for the new local time.
*/
constructor(hour, minute, second, nanosecond) {
- this.hour = hour;
- this.minute = minute;
- this.second = second;
- this.nanosecond = nanosecond;
+ this.hour = assertNumberOrInteger(hour, 'Hour');
+ this.minute = assertNumberOrInteger(minute, 'Minute');
+ this.second = assertNumberOrInteger(second, 'Second');
+ this.nanosecond = assertNumberOrInteger(nanosecond, 'Nanosecond');
Object.freeze(this);
}
@@ -122,11 +125,11 @@ export class Time {
* @param {Integer|number} timeZoneOffsetSeconds the time zone offset in seconds.
*/
constructor(hour, minute, second, nanosecond, timeZoneOffsetSeconds) {
- this.hour = hour;
- this.minute = minute;
- this.second = second;
- this.nanosecond = nanosecond;
- this.timeZoneOffsetSeconds = timeZoneOffsetSeconds;
+ this.hour = assertNumberOrInteger(hour, 'Hour');
+ this.minute = assertNumberOrInteger(minute, 'Minute');
+ this.second = assertNumberOrInteger(second, 'Second');
+ this.nanosecond = assertNumberOrInteger(nanosecond, 'Nanosecond');
+ this.timeZoneOffsetSeconds = assertNumberOrInteger(timeZoneOffsetSeconds, 'Time zone offset in seconds');
Object.freeze(this);
}
@@ -159,9 +162,9 @@ export class Date {
* @param {Integer|number} day the day for the new local date.
*/
constructor(year, month, day) {
- this.year = year;
- this.month = month;
- this.day = day;
+ this.year = assertNumberOrInteger(year, 'Year');
+ this.month = assertNumberOrInteger(month, 'Month');
+ this.day = assertNumberOrInteger(day, 'Day');
Object.freeze(this);
}
@@ -198,13 +201,13 @@ export class LocalDateTime {
* @param {Integer|number} nanosecond the nanosecond for the new local time.
*/
constructor(year, month, day, hour, minute, second, nanosecond) {
- this.year = year;
- this.month = month;
- this.day = day;
- this.hour = hour;
- this.minute = minute;
- this.second = second;
- this.nanosecond = nanosecond;
+ this.year = assertNumberOrInteger(year, 'Year');
+ this.month = assertNumberOrInteger(month, 'Month');
+ this.day = assertNumberOrInteger(day, 'Day');
+ this.hour = assertNumberOrInteger(hour, 'Hour');
+ this.minute = assertNumberOrInteger(minute, 'Minute');
+ this.second = assertNumberOrInteger(second, 'Second');
+ this.nanosecond = assertNumberOrInteger(nanosecond, 'Nanosecond');
Object.freeze(this);
}
@@ -243,13 +246,13 @@ export class DateTime {
* @param {string|null} timeZoneId the time zone id for the new date-time. Either this argument or timeZoneOffsetSeconds
should be defined.
*/
constructor(year, month, day, hour, minute, second, nanosecond, timeZoneOffsetSeconds, timeZoneId) {
- this.year = year;
- this.month = month;
- this.day = day;
- this.hour = hour;
- this.minute = minute;
- this.second = second;
- this.nanosecond = nanosecond;
+ this.year = assertNumberOrInteger(year, 'Year');
+ this.month = assertNumberOrInteger(month, 'Month');
+ this.day = assertNumberOrInteger(day, 'Day');
+ this.hour = assertNumberOrInteger(hour, 'Hour');
+ this.minute = assertNumberOrInteger(minute, 'Minute');
+ this.second = assertNumberOrInteger(second, 'Second');
+ this.nanosecond = assertNumberOrInteger(nanosecond, 'Nanosecond');
const [offset, id] = verifyTimeZoneArguments(timeZoneOffsetSeconds, timeZoneId);
this.timeZoneOffsetSeconds = offset;
@@ -289,8 +292,10 @@ function verifyTimeZoneArguments(timeZoneOffsetSeconds, timeZoneId) {
const idDefined = timeZoneId && timeZoneId !== '';
if (offsetDefined && !idDefined) {
+ assertNumberOrInteger(timeZoneOffsetSeconds, 'Time zone offset in seconds');
return [timeZoneOffsetSeconds, null];
} else if (!offsetDefined && idDefined) {
+ assertString(timeZoneId, 'Time zone ID');
return [null, timeZoneId];
} else if (offsetDefined && idDefined) {
throw newError(`Unable to create DateTime with both time zone offset and id. Please specify either of them. Given offset: ${timeZoneOffsetSeconds} and id: ${timeZoneId}`);
diff --git a/test/internal/http/http-driver.test.js b/test/internal/http/http-driver.test.js
index 3d183b750..a82f1a054 100644
--- a/test/internal/http/http-driver.test.js
+++ b/test/internal/http/http-driver.test.js
@@ -346,7 +346,7 @@ describe('http driver', () => {
return;
}
- testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.LocalDateTime(2000, 10, 12, 10, 10, 10), done);
+ testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.LocalDateTime(2000, 10, 12, 10, 10, 10, 10), done);
});
it('should fail to pass local time as a query parameter', done => {
diff --git a/test/internal/util.test.js b/test/internal/util.test.js
index bd25fab32..58cc873d6 100644
--- a/test/internal/util.test.js
+++ b/test/internal/util.test.js
@@ -18,6 +18,7 @@
*/
import * as util from '../../src/v1/internal/util';
+import {int} from '../../src/v1';
describe('util', () => {
@@ -93,6 +94,47 @@ describe('util', () => {
verifyInvalidQueryParameters(() => null);
});
+ it('should check numbers and integers', () => {
+ verifyValidNumber(0);
+ verifyValidNumber(1);
+ verifyValidNumber(42);
+ verifyValidNumber(-42);
+ verifyValidNumber(12.001);
+ verifyValidNumber(-493.423);
+
+ verifyInvalidNumber(int(0));
+ verifyInvalidNumber(int(1));
+ verifyInvalidNumber(int(147123));
+ verifyInvalidNumber('');
+ verifyInvalidNumber('42');
+ verifyInvalidNumber([]);
+ verifyInvalidNumber([42]);
+ verifyInvalidNumber({});
+ verifyInvalidNumber({value: 42});
+ });
+
+ it('should check numbers and integers', () => {
+ verifyValidNumberOrInteger(0);
+ verifyValidNumberOrInteger(1);
+ verifyValidNumberOrInteger(42);
+ verifyValidNumberOrInteger(-42);
+ verifyValidNumberOrInteger(12.001);
+ verifyValidNumberOrInteger(-493.423);
+
+ verifyValidNumberOrInteger(int(0));
+ verifyValidNumberOrInteger(int(42));
+ verifyValidNumberOrInteger(int(1241));
+ verifyValidNumberOrInteger(int(441));
+ verifyValidNumberOrInteger(int(-100500));
+
+ verifyInvalidNumberOrInteger('');
+ verifyInvalidNumberOrInteger('42');
+ verifyInvalidNumberOrInteger([]);
+ verifyInvalidNumberOrInteger([42]);
+ verifyInvalidNumberOrInteger({});
+ verifyInvalidNumberOrInteger({value: 42});
+ });
+
function verifyValidString(str) {
expect(util.assertString(str, 'Test string')).toBe(str);
}
@@ -101,6 +143,22 @@ describe('util', () => {
expect(() => util.assertString(str, 'Test string')).toThrowError(TypeError);
}
+ function verifyValidNumber(obj) {
+ expect(util.assertNumber(obj, 'Test number')).toBe(obj);
+ }
+
+ function verifyInvalidNumber(obj) {
+ expect(() => util.assertNumber(obj, 'Test number')).toThrowError(TypeError);
+ }
+
+ function verifyValidNumberOrInteger(obj) {
+ expect(util.assertNumberOrInteger(obj, 'Test object')).toEqual(obj);
+ }
+
+ function verifyInvalidNumberOrInteger(obj) {
+ expect(() => util.assertNumberOrInteger(obj, 'Test object')).toThrowError(TypeError);
+ }
+
function verifyInvalidCypherStatement(str) {
expect(() => util.validateStatementAndParameters(str, {})).toThrowError(TypeError);
}
diff --git a/test/v1/spatial-types.test.js b/test/v1/spatial-types.test.js
index 62dd7a439..5ae9d5578 100644
--- a/test/v1/spatial-types.test.js
+++ b/test/v1/spatial-types.test.js
@@ -17,7 +17,7 @@
* limitations under the License.
*/
-import neo4j from '../../src/v1';
+import neo4j, {int} from '../../src/v1';
import sharedNeo4j from '../internal/shared-neo4j';
import {ServerVersion, VERSION_3_4_0} from '../../src/v1/internal/server-version';
import {isPoint, Point} from '../../src/v1/spatial-types';
@@ -210,6 +210,35 @@ describe('spatial-types', () => {
expect(point6.toString()).toEqual('Point{srid=7203, x=23.9378123, y=67.3891}');
});
+ it('should validate types of constructor arguments for Point', () => {
+ expect(() => new Point('1', 2, 3)).toThrowError(TypeError);
+ expect(() => new Point(1, '2', 3)).toThrowError(TypeError);
+ expect(() => new Point(1, 2, '3')).toThrowError(TypeError);
+ expect(() => new Point(1, 2, '3')).toThrowError(TypeError);
+
+ expect(() => new Point('1', 2, 3, null)).toThrowError(TypeError);
+ expect(() => new Point(1, '2', 3, null)).toThrowError(TypeError);
+ expect(() => new Point(1, 2, '3', null)).toThrowError(TypeError);
+ expect(() => new Point(1, 2, '3', null)).toThrowError(TypeError);
+
+ expect(() => new Point('1', 2, 3, 4)).toThrowError(TypeError);
+ expect(() => new Point(1, '2', 3, 4)).toThrowError(TypeError);
+ expect(() => new Point(1, 2, '3', 4)).toThrowError(TypeError);
+ expect(() => new Point(1, 2, '3', 4)).toThrowError(TypeError);
+
+ expect(() => new Point(1, int(2), 3, 4)).toThrowError(TypeError);
+ expect(() => new Point(1, 2, int(3), 4)).toThrowError(TypeError);
+ expect(() => new Point(1, 2, 3, int(4))).toThrowError(TypeError);
+
+ expect(new Point(1, 2, 3, 4)).toBeDefined();
+
+ expect(new Point(int(1), 2, 3, undefined)).toBeDefined();
+ expect(new Point(1, 2, 3, undefined)).toBeDefined();
+
+ expect(new Point(1, 2, 3, null)).toBeDefined();
+ expect(new Point(int(1), 2, 3, null)).toBeDefined();
+ });
+
function testReceivingOfPoints(done, query, pointChecker) {
if (neo4jDoesNotSupportPoints(done)) {
return;
diff --git a/test/v1/temporal-types.test.js b/test/v1/temporal-types.test.js
index d764ef07c..cbc926f12 100644
--- a/test/v1/temporal-types.test.js
+++ b/test/v1/temporal-types.test.js
@@ -513,7 +513,7 @@ describe('temporal-types', () => {
});
it('should expose local date-time components in date-time with zone ID', () => {
- const zonedDateTime = dateTimeWithZoneId(2356, 7, 29, 23, 32, 11, 9346458, 3600, randomZoneId());
+ const zonedDateTime = dateTimeWithZoneId(2356, 7, 29, 23, 32, 11, 9346458, randomZoneId());
expect(zonedDateTime.year).toEqual(neo4j.int(2356));
expect(zonedDateTime.month).toEqual(neo4j.int(7));
@@ -597,6 +597,67 @@ describe('temporal-types', () => {
expect(duration6.nanoseconds).toEqual(neo4j.int(876543001));
});
+ it('should validate types of constructor arguments for Duration', () => {
+ expect(() => new neo4j.types.Duration('1', 2, 3, 4)).toThrowError(TypeError);
+ expect(() => new neo4j.types.Duration(1, '2', 3, 4)).toThrowError(TypeError);
+ expect(() => new neo4j.types.Duration(1, 2, [3], 4)).toThrowError(TypeError);
+ expect(() => new neo4j.types.Duration(1, 2, 3, {value: 4})).toThrowError(TypeError);
+ expect(() => new neo4j.types.Duration({months: 1, days: 2, seconds: 3, nanoseconds: 4})).toThrowError(TypeError);
+ });
+
+ it('should validate types of constructor arguments for LocalTime', () => {
+ expect(() => new neo4j.types.LocalTime('1', 2, 3, 4)).toThrowError(TypeError);
+ expect(() => new neo4j.types.LocalTime(1, '2', 3, 4)).toThrowError(TypeError);
+ expect(() => new neo4j.types.LocalTime(1, 2, [3], 4)).toThrowError(TypeError);
+ expect(() => new neo4j.types.LocalTime(1, 2, 3, {value: 4})).toThrowError(TypeError);
+ expect(() => new neo4j.types.LocalTime({hour: 1, minute: 2, seconds: 3, nanosecond: 4})).toThrowError(TypeError);
+ });
+
+ it('should validate types of constructor arguments for Time', () => {
+ expect(() => new neo4j.types.Time('1', 2, 3, 4, 5)).toThrowError(TypeError);
+ expect(() => new neo4j.types.Time(1, '2', 3, 4, 5)).toThrowError(TypeError);
+ expect(() => new neo4j.types.Time(1, 2, [3], 4, 5)).toThrowError(TypeError);
+ expect(() => new neo4j.types.Time(1, 2, 3, {value: 4}, 5)).toThrowError(TypeError);
+ expect(() => new neo4j.types.Time(1, 2, 3, 4, () => 5)).toThrowError(TypeError);
+ expect(() => new neo4j.types.Time({hour: 1, minute: 2, seconds: 3, nanosecond: 4, timeZoneOffsetSeconds: 5})).toThrowError(TypeError);
+ });
+
+ it('should validate types of constructor arguments for Date', () => {
+ expect(() => new neo4j.types.Date('1', 2, 3)).toThrowError(TypeError);
+ expect(() => new neo4j.types.Date(1, [2], 3)).toThrowError(TypeError);
+ expect(() => new neo4j.types.Date(1, 2, () => 3)).toThrowError(TypeError);
+ expect(() => new neo4j.types.Date({year: 1, month: 2, day: 3})).toThrowError(TypeError);
+ });
+
+ it('should validate types of constructor arguments for LocalDateTime', () => {
+ expect(() => new neo4j.types.LocalDateTime('1', 2, 3, 4, 5, 6, 7)).toThrowError(TypeError);
+ expect(() => new neo4j.types.LocalDateTime(1, '2', 3, 4, 5, 6, 7)).toThrowError(TypeError);
+ expect(() => new neo4j.types.LocalDateTime(1, 2, [3], 4, 5, 6, 7)).toThrowError(TypeError);
+ expect(() => new neo4j.types.LocalDateTime(1, 2, 3, [4], 5, 6, 7)).toThrowError(TypeError);
+ expect(() => new neo4j.types.LocalDateTime(1, 2, 3, 4, () => 5, 6, 7)).toThrowError(TypeError);
+ expect(() => new neo4j.types.LocalDateTime(1, 2, 3, 4, 5, () => 6, 7)).toThrowError(TypeError);
+ expect(() => new neo4j.types.LocalDateTime(1, 2, 3, 4, 5, 6, {value: 7})).toThrowError(TypeError);
+ expect(() => new neo4j.types.LocalDateTime({year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6, nanosecond: 7})).toThrowError(TypeError);
+ });
+
+ it('should validate types of constructor arguments for DateTime', () => {
+ expect(() => new neo4j.types.DateTime('1', 2, 3, 4, 5, 6, 7, 8)).toThrowError(TypeError);
+ expect(() => new neo4j.types.DateTime(1, '2', 3, 4, 5, 6, 7, 8)).toThrowError(TypeError);
+ expect(() => new neo4j.types.DateTime(1, 2, [3], 4, 5, 6, 7, 8)).toThrowError(TypeError);
+ expect(() => new neo4j.types.DateTime(1, 2, 3, [4], 5, 6, 7, 8)).toThrowError(TypeError);
+ expect(() => new neo4j.types.DateTime(1, 2, 3, 4, () => 5, 6, 7, 8)).toThrowError(TypeError);
+ expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, () => 6, 7, 8)).toThrowError(TypeError);
+ expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, {value: 7}, 8)).toThrowError(TypeError);
+ expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, {value: 8})).toThrowError(TypeError);
+
+ expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, null, {timeZoneId: 'UK'})).toThrowError(TypeError);
+ expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, null, ['UK'])).toThrowError(TypeError);
+
+ expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7)).toThrow();
+ expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, null, null)).toThrow();
+ expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, 8, 'UK')).toThrow();
+ });
+
function testSendAndReceiveRandomTemporalValues(valueGenerator, done) {
const asyncFunction = (index, callback) => {
const next = () => callback();