diff options
author | Nick Zolnierz <nicholas.zolnierz@mongodb.com> | 2018-01-30 13:10:47 -0500 |
---|---|---|
committer | Nick Zolnierz <nicholas.zolnierz@mongodb.com> | 2018-02-21 13:33:36 -0500 |
commit | 1e9e5f85d3d9ae42ea80a48b593be45306724831 (patch) | |
tree | 6ffaca9b84c1117fe6cf4b9e33e720463898b9db /jstests | |
parent | f15200621c45cf27bc348eaa1e0573372fc6ff93 (diff) | |
download | mongo-1e9e5f85d3d9ae42ea80a48b593be45306724831.tar.gz |
SERVER-32736: Add "onError" and "onNull" options to $dateFromString
Diffstat (limited to 'jstests')
3 files changed, 293 insertions, 21 deletions
diff --git a/jstests/aggregation/expressions/date_from_string.js b/jstests/aggregation/expressions/date_from_string.js index 9dfe4a355b4..e62b4f9f392 100644 --- a/jstests/aggregation/expressions/date_from_string.js +++ b/jstests/aggregation/expressions/date_from_string.js @@ -593,8 +593,10 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode and assertE ]; pipelines.forEach(function(pipeline) { - assertErrMsgContains( - coll, pipeline, 40545, "an incomplete date/time string has been found"); + assertErrMsgContains(coll, + pipeline, + ErrorCodes.ConversionFailure, + "an incomplete date/time string has been found"); }); /* --------------------------------------------------------------------------------------- */ @@ -612,7 +614,8 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode and assertE ]; pipelines.forEach(function(pipeline) { - assertErrMsgContains(coll, pipeline, 40553, "Error parsing date string"); + assertErrMsgContains( + coll, pipeline, ErrorCodes.ConversionFailure, "Error parsing date string"); }); /* --------------------------------------------------------------------------------------- */ @@ -670,8 +673,10 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode and assertE assertErrMsgContains(coll, pipeline, 40541, "Unrecognized argument"); pipeline = [{$project: {date: {$dateFromString: {dateString: 5}}}}]; - assertErrMsgContains( - coll, pipeline, 40543, "$dateFromString requires that 'dateString' be a string"); + assertErrMsgContains(coll, + pipeline, + ErrorCodes.ConversionFailure, + "$dateFromString requires that 'dateString' be a string"); /* --------------------------------------------------------------------------------------- */ /* Passing in time zone with date/time string. */ @@ -684,7 +689,7 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode and assertE } } }; - assertErrorCode(coll, pipeline, 40554); + assertErrorCode(coll, pipeline, ErrorCodes.ConversionFailure); pipeline = { $project: { @@ -694,7 +699,7 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode and assertE } } }; - assertErrorCode(coll, pipeline, 40551); + assertErrorCode(coll, pipeline, ErrorCodes.ConversionFailure); pipeline = { $project: { @@ -706,26 +711,26 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode and assertE } } }; - assertErrorCode(coll, pipeline, 40553); + assertErrorCode(coll, pipeline, ErrorCodes.ConversionFailure); pipeline = { $project: {date: {$dateFromString: {dateString: "2017-07-12T22:23:55 Europe/Amsterdam"}}} }; - assertErrorCode(coll, pipeline, 40553); + assertErrorCode(coll, pipeline, ErrorCodes.ConversionFailure); /* --------------------------------------------------------------------------------------- */ /* Error cases for $dateFromString with format specifier string. */ // Test umatched format specifier string. pipeline = [{$project: {date: {$dateFromString: {dateString: "2018-01", format: "%Y-%m-%d"}}}}]; - assertErrMsgContains(coll, pipeline, 40553, "Data missing"); + assertErrMsgContains(coll, pipeline, ErrorCodes.ConversionFailure, "Data missing"); pipeline = [{$project: {date: {$dateFromString: {dateString: "2018-01", format: "%Y"}}}}]; - assertErrMsgContains(coll, pipeline, 40553, "Trailing data"); + assertErrMsgContains(coll, pipeline, ErrorCodes.ConversionFailure, "Trailing data"); // Test missing specifier prefix '%'. pipeline = [{$project: {date: {$dateFromString: {dateString: "1992-26-04", format: "Y-d-m"}}}}]; - assertErrMsgContains(coll, pipeline, 40553, "Format literal not found"); + assertErrMsgContains(coll, pipeline, ErrorCodes.ConversionFailure, "Format literal not found"); pipeline = [{$project: {date: {$dateFromString: {dateString: "1992", format: "%n"}}}}]; assertErrMsgContains(coll, pipeline, 18536, "Invalid format character"); @@ -741,7 +746,7 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode and assertE assertErrMsgContains( coll, pipeline, - 40554, + ErrorCodes.ConversionFailure, "you cannot pass in a date/time string with GMT offset together with a timezone argument"); pipeline = [{$project: {date: {$dateFromString: {dateString: "4/26/1992", format: 5}}}}]; @@ -754,31 +759,37 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode and assertE pipeline = [{$project: {date: {$dateFromString: {dateString: "ISO Day 6", format: "ISO Day %u"}}}}]; - assertErrMsgContains(coll, pipeline, 40553, "The parsed date was invalid"); + assertErrMsgContains( + coll, pipeline, ErrorCodes.ConversionFailure, "The parsed date was invalid"); pipeline = [{$project: {date: {$dateFromString: {dateString: "ISO Week 52", format: "ISO Week %V"}}}}]; - assertErrMsgContains(coll, pipeline, 40553, "The parsed date was invalid"); + assertErrMsgContains( + coll, pipeline, ErrorCodes.ConversionFailure, "The parsed date was invalid"); pipeline = [{ $project: { date: {$dateFromString: {dateString: "ISO Week 1, 2018", format: "ISO Week %V, %Y"}} } }]; - assertErrMsgContains( - coll, pipeline, 40553, "Mixing of ISO dates with natural dates is not allowed"); + assertErrMsgContains(coll, + pipeline, + ErrorCodes.ConversionFailure, + "Mixing of ISO dates with natural dates is not allowed"); pipeline = [{$project: {date: {$dateFromString: {dateString: "12/31/2018", format: "%m/%d/%G"}}}}]; - assertErrMsgContains( - coll, pipeline, 40553, "Mixing of ISO dates with natural dates is not allowed"); + assertErrMsgContains(coll, + pipeline, + ErrorCodes.ConversionFailure, + "Mixing of ISO dates with natural dates is not allowed"); // Test embedded null bytes in the 'dateString' and 'format' fields. pipeline = [{$project: {date: {$dateFromString: {dateString: "12/31\0/2018", format: "%m/%d/%Y"}}}}]; - assertErrMsgContains(coll, pipeline, 40553, "Data missing"); + assertErrMsgContains(coll, pipeline, ErrorCodes.ConversionFailure, "Data missing"); pipeline = [{$project: {date: {$dateFromString: {dateString: "12/31/2018", format: "%m/%d\0/%Y"}}}}]; - assertErrMsgContains(coll, pipeline, 40553, "Trailing data"); + assertErrMsgContains(coll, pipeline, ErrorCodes.ConversionFailure, "Trailing data"); })(); diff --git a/jstests/aggregation/expressions/date_from_string_on_error.js b/jstests/aggregation/expressions/date_from_string_on_error.js new file mode 100644 index 00000000000..ba0ce0fa573 --- /dev/null +++ b/jstests/aggregation/expressions/date_from_string_on_error.js @@ -0,0 +1,193 @@ +/** + * Tests for the $dateFromString expression with the optional 'onError' parameter. + */ +(function() { + "use strict"; + + load("jstests/aggregation/extras/utils.js"); // For assertErrMsgContains. + + const onErrorValue = ISODate("2017-07-04T11:56:02Z"); + const coll = db.date_from_string_on_error; + coll.drop(); + + assert.writeOK(coll.insert({_id: 0})); + + // Test that the 'onError' value is returned when 'dateString' is not a valid date/time. + for (let inputDate of["July 4th", + "12:50:53", + "2017", + "60.Monday1770/06:59", + "Not even close", + "July 4th, 10000"]) { + assert.eq( + [{_id: 0, date: onErrorValue}], + coll.aggregate({ + $project: + {date: {$dateFromString: {dateString: inputDate, onError: onErrorValue}}} + }) + .toArray()); + } + + // Test that the 'onError' value is returned when 'dateString' is not a string. + for (let inputDate of[5, {year: 2018, month: 2, day: 5}, ["2018-02-05"]]) { + assert.eq( + [{_id: 0, date: onErrorValue}], + coll.aggregate({ + $project: + {date: {$dateFromString: {dateString: inputDate, onError: onErrorValue}}} + }) + .toArray()); + } + + // Test that the 'onError' value is ignored when 'dateString' is nullish. + for (let inputDate of[null, undefined, "$missing"]) { + assert.eq( + [{_id: 0, date: null}], + coll.aggregate({ + $project: + {date: {$dateFromString: {dateString: inputDate, onError: onErrorValue}}} + }) + .toArray()); + } + + // Test that the 'onError' value is returned for unmatched format strings. + for (let inputFormat of["%Y", "%Y-%m-%dT%H", "Y-m-d"]) { + assert.eq([{_id: 0, date: onErrorValue}], + coll.aggregate({ + $project: { + date: { + $dateFromString: { + dateString: "2018-02-06", + format: inputFormat, + onError: onErrorValue + } + } + } + }) + .toArray()); + } + + // Test that null is returned when the 'timezone' or 'format' is nullish, regardless of the + // 'onError' value. + for (let nullishValue of[null, undefined, "$missing"]) { + assert.eq([{_id: 0, date: null}], + coll.aggregate({ + $project: { + date: { + $dateFromString: { + dateString: "2018-02-06T11:56:02Z", + format: nullishValue, + onError: onErrorValue + } + } + } + }) + .toArray()); + assert.eq([{_id: 0, date: null}], + coll.aggregate({ + $project: { + date: { + $dateFromString: { + dateString: "2018-02-06T11:56:02Z", + timezone: nullishValue, + onError: onErrorValue + } + } + } + }) + .toArray()); + } + + // Test that onError is returned when the input is not a string and other parameters are + // nullish. + assert.eq( + [{_id: 0, date: onErrorValue}], + coll.aggregate({ + $project: { + date: {$dateFromString: {dateString: 5, format: null, onError: onErrorValue}} + } + }) + .toArray()); + assert.eq([{_id: 0, date: onErrorValue}], + coll.aggregate({ + $project: { + date: { + $dateFromString: + {dateString: 5, timezone: "$missing", onError: onErrorValue} + } + } + }) + .toArray()); + + // Test that onError is ignored when the input is an invalid string and other parameters are + // nullish. + assert.eq([{_id: 0, date: null}], + coll.aggregate({ + $project: { + date: { + $dateFromString: { + dateString: "Invalid date string", + format: null, + onError: onErrorValue + } + } + } + }) + .toArray()); + assert.eq([{_id: 0, date: null}], + coll.aggregate({ + $project: { + date: { + $dateFromString: { + dateString: "Invalid date string", + timezone: "$missing", + onError: onErrorValue + } + } + } + }) + .toArray()); + + // Test that 'onError' can be any type, not just an ISODate. + for (let onError of[{}, 5, "Not a date", null, undefined]) { + assert.eq( + [{_id: 0, date: onError}], + coll.aggregate({ + $project: {date: {$dateFromString: {dateString: "invalid", onError: onError}}} + }) + .toArray()); + } + // Test that a missing 'onError' value results in no output field when used within a $project + // stage. + assert.eq( + [{_id: 0}], + coll.aggregate( + {$project: {date: {$dateFromString: {dateString: "invalid", onError: "$missing"}}}}) + .toArray()); + + // Test that 'onError' is ignored when the 'format' is invalid. + assertErrMsgContains( + coll, + [{ + $project: { + date: { + $dateFromString: {dateString: "4/26/1992", format: 5, onError: onErrorValue} + } + } + }], + 40684, + "$dateFromString requires that 'format' be a string"); + + assertErrMsgContains( + coll, + [{ + $project: { + date: { + $dateFromString: + {dateString: "4/26/1992", format: "%n", onError: onErrorValue} + } + } + }], + 18536, + "Invalid format character '%n' in format string"); +})(); diff --git a/jstests/aggregation/expressions/date_from_string_on_null.js b/jstests/aggregation/expressions/date_from_string_on_null.js new file mode 100644 index 00000000000..12b7d673984 --- /dev/null +++ b/jstests/aggregation/expressions/date_from_string_on_null.js @@ -0,0 +1,68 @@ +/** + * Tests for the $dateFromString expression with the optional 'onNull' parameter. + */ +(function() { + "use strict"; + + const onNullValue = ISODate("2017-07-04T11:56:02Z"); + const coll = db.date_from_string_on_null; + coll.drop(); + + assert.writeOK(coll.insert({_id: 0})); + + // Test that the 'onNull' value is returned when the 'dateString' is nullish. + for (let inputDate of[null, undefined, "$missing"]) { + assert.eq( + [{_id: 0, date: onNullValue}], + coll.aggregate({ + $project: + {date: {$dateFromString: {dateString: inputDate, onNull: onNullValue}}} + }) + .toArray()); + } + + // Test that null is returned when the 'timezone' or 'format' is nullish, regardless of the + // 'onNull' value. + for (let nullishValue of[null, undefined, "$missing"]) { + assert.eq([{_id: 0, date: null}], + coll.aggregate({ + $project: { + date: { + $dateFromString: { + dateString: "2018-02-06T11:56:02Z", + format: nullishValue, + onNull: onNullValue + } + } + } + }) + .toArray()); + assert.eq([{_id: 0, date: null}], + coll.aggregate({ + $project: { + date: { + $dateFromString: { + dateString: "2018-02-06T11:56:02Z", + timezone: nullishValue, + onNull: onNullValue + } + } + } + }) + .toArray()); + } + + // Test that 'onNull' can be any type, not just an ISODate. + for (let onNull of[{}, 5, "Not a date", null, undefined]) { + assert.eq( + [{_id: 0, date: onNull}], + coll.aggregate( + {$project: {date: {$dateFromString: {dateString: "$missing", onNull: onNull}}}}) + .toArray()); + } + assert.eq( + [{_id: 0}], + coll.aggregate( + {$project: {date: {$dateFromString: {dateString: "$missing", onNull: "$missing"}}}}) + .toArray()); +})(); |