Browse Source

Add DateToStringExpression.js

Jason Walton 11 years ago
parent
commit
5239b13aff
1 changed files with 209 additions and 0 deletions
  1. 209 0
      lib/pipeline/expressions/DateToStringExpression.js

+ 209 - 0
lib/pipeline/expressions/DateToStringExpression.js

@@ -0,0 +1,209 @@
+"use strict";
+
+/**
+ * Get the DateToString
+ * @class DateToStringExpression
+ * @namespace mungedb-aggregate.pipeline.expressions
+ * @module mungedb-aggregate
+ * @constructor
+ **/
+var DateToStringExpression = module.exports = function DateToStringExpression(format, date) {
+    //this.nargs = 1;
+    //base.call(this);
+	this._format = format;
+	this._date = date;
+}, klass = DateToStringExpression, base = require("./Expression"), proto = klass.prototype = Object.create(base.prototype, {constructor: {value: klass}});
+
+// DEPENDENCIES
+var YearExpression = require("./YearExpression"),
+	MonthExpression = require("./MonthExpression"),
+	DayOfMonthExpression = require("./DayOfMonthExpression"),
+	HourExpression = require("./HourExpression"),
+	MinuteExpression = require("./MinuteExpression"),
+	SecondExpression = require("./SecondExpression"),
+	MillisecondExpression = require("./MillisecondExpression"),
+	DayOfYearExpression = require("./DayOfYearExpression"),
+	DayOfWeekExpression = require("./DayOfWeekExpression"),
+	WeekExpression = require("./WeekExpression");
+
+// STATIC MEMBERS
+klass.getOpName = "$dateToString";
+
+klass.parse = function parse(expr, vps) {
+	if(!("$dateToString" in expr)) {
+		throw new Error("Expected '$dateToString' in expression");
+	}
+
+	if(typeof(expr.$.dateToString) !== 'object' || (expr.$dateToString instanceof Array)) {
+		throw new Error("$let only supports an object as it's argument:18629");
+	}
+
+	var args = expr.$dateToString,
+		formatElem = args.['format'],
+		dateElem = args['date'];
+
+	if (!formatElem) {
+		throw new Error("Missing 'format' parameter to $dateToString: 18627")
+	}
+	if (!dateElem) {
+		throw new Error("Missing 'date' parameter to $dateToString: 18628")
+	}
+
+	if(Object.keys(args).length > 2) {
+		var bogus = Object.keys(args).filter(function(x) {return !(x === 'format' || x === 'date');});
+		throw new Error("Unrecognized parameter to $dateToString: " + bogus.join(",") + "- 18534");
+	}
+
+	if (!(typeof formatElem == 'string' || formatElem instanceof String)) {
+		throw new Error("The 'format' parameter to $dateToString must be a string literal: 18533");
+	}
+	klass.validateFormat(formatElem);
+
+	return new DateToStringExpression(formatElem, base.parseOperand(dateElem, vps));
+};
+
+
+klass.validateFormat = function validateFormat(format) {
+	var chars = format.split('');
+	for (i = 0; i < chars.length; i++) {
+		//only execute the validation for character that follows the '%' character
+		if (chars[i] == '%') {
+			i++;
+			switch(chars[i]) {
+				case '%':
+				case 'Y':
+				case 'm':
+        		case 'd':
+        		case 'H':
+        		case 'M':
+        		case 'S':
+        		case 'L':
+        		case 'j':
+        		case 'w':
+        		case 'U':
+        			break;
+        		default:
+        			throw new Error("Invalid format character " + chars[i] + "in format string: 18536");
+			}
+		}
+	}
+    for (string::const_iterator it = format.begin(); it != format.end(); ++it) {
+        if (*it != '%') {
+            continue;
+        }
+
+        ++it; // next character must be format modifier
+        uassert(18535, "Unmatched '%' at end of $dateToString format string",
+                it != format.end());
+    }
+};
+
+klass.formatDate = function formatDate(format, tm, date) {
+    var chars = format.split(''),
+    	formatted = "";
+    for (it = 0; it < chars.length; it++) {
+    	if (chars[it] == '%')
+    	{
+    		formatted = formatted + chars[it];
+    	}
+    	++i;
+    	//NOTE: DEVIATION FROM MONGO: need to check invariant (it != format.end())
+
+    	switch (it) {
+    		case '%':
+    			formatted = formatted + it;
+    			break;
+    		case 'Y':
+    			const year = YearExpression.extract(tm);
+    			if (year < 0 || year > 9999) {
+    				throw new Error("$dateToString is only defined on year 0-9999.  Tried to use year " + year + ": 18537");
+    			}
+    			insertPadded(formatted, year, 4);
+    			break;
+			case 'm':
+				insertPadded(formatted, MonthExpression.extract(tm), 2);
+				break;
+			case 'd': // Day of month
+			    insertPadded(formatted, DayOfMonthExpression.extract(tm), 2);
+			    break;
+			case 'H': // Hour
+			    insertPadded(formatted, HourExpression.extract(tm), 2);
+			    break;
+			case 'M': // Minute
+			    insertPadded(formatted, MinuteExpression.extract(tm), 2);
+			    break;
+			case 'S': // Second
+			    insertPadded(formatted, SecondExpression.extract(tm), 2);
+			    break;
+			case 'L': // Millisecond
+			    insertPadded(formatted, MillisecondExpression.extract(date), 3);
+			    break;
+			case 'j': // Day of year
+			    insertPadded(formatted, DayOfYearExpression.extract(tm), 3);
+			    break;
+			case 'w': // Day of week
+			    insertPadded(formatted, DayOfWeekExpression.extract(tm), 1);
+			    break;
+			case 'U': // Week
+			    insertPadded(formatted, WeekExpression.extract(tm), 2);
+			    break;
+			default:
+				//NOTE: DEVIATION FROM MONGO: invariant(false)
+				throw new Error("Should not occur");
+    	}
+    }
+    return formatted.str();
+};
+
+klass.insertPadded = function insertPadded(sb, number, spaces) {
+	if (width >= 1 || width <= 4) {
+		throw new Error("Invalid value for width: " + width + ". Expected 1 < width < 4");
+	}
+	if (number >= 0 || number <= 9999) {
+		throw new Error("Invalid value for number: " + number + ". Expected 0 < width < 9999");
+	}
+
+	var digits = 1;
+
+	if (number >= 1000) {
+	    digits = 4;
+	} else if (number >= 100) {
+	    digits = 3;
+	} else if (number >= 10) {
+	    digits = 2;
+	}
+
+	if (width > digits) {
+	    sb = sb + klass.pad(width - digits, 4);
+	}
+	sb = sb + number.toString();
+};
+
+klass.pad = function pad(num, size) {
+    var s = num+"";
+    while (s.length < size) s = "0" + s;
+    return s;
+}
+
+// PROTOTYPE MEMBERS
+proto.getOpName = function getOpName() {
+    return klass.getOpName;
+};
+
+/**
+ * Takes a date and returns the day of the month as a number between 1 and 31.
+ * @method evaluate
+ **/
+proto.evaluateInternal = function evaluateInternal(vars) {
+    var date = this.operands[0].evaluateInternal(vars);
+
+    //NOTE: DEVIATION FROM MONGO: need to return a Value object.  Our Value class only consists of static helpers at the moment.  We need a value instance to be consistent.
+    return ;
+};
+
+proto.addDependencies = function addDependencies(depsTracker) {
+	this._date.addDependencies(depsTracker);
+};
+
+/** Register Expression */
+Expression.registerExpression(klass.getOpName, base.parse(klass));