modifyjs
Version:
Modify your objects with a mongo syntax.
153 lines (146 loc) • 4.32 kB
JavaScript
import { isArray } from './helpers';
import { EJSON } from './ejson';
export var _f = {
// XXX for _all and _in, consider building 'inquery' at compile time..
_type: function _type(v) {
if (typeof v === "number") return 1;
if (typeof v === "string") return 2;
if (typeof v === "boolean") return 8;
if (isArray(v)) return 4;
if (v === null) return 10;
if (v instanceof RegExp)
// note that typeof(/x/) === "object"
return 11;
if (typeof v === "function") return 13;
if (v instanceof Date) return 9;
if (EJSON.isBinary(v)) return 5;
return 3; // object
// XXX support some/all of these:
// 14, symbol
// 15, javascript code with scope
// 16, 18: 32-bit/64-bit integer
// 17, timestamp
// 255, minkey
// 127, maxkey
},
// deep equality test: use for literal document and array matches
_equal: function _equal(a, b) {
return EJSON.equals(a, b, { keyOrderSensitive: true });
},
// maps a type code to a value that can be used to sort values of
// different types
_typeorder: function _typeorder(t) {
// http://www.mongodb.org/display/DOCS/What+is+the+Compare+Order+for+BSON+Types
// XXX what is the correct sort position for Javascript code?
// ('100' in the matrix below)
// XXX minkey/maxkey
return [-1, // (not a type)
1, // number
2, // string
3, // object
4, // array
5, // binary
-1, // deprecated
6, // ObjectID
7, // bool
8, // Date
0, // null
9, // RegExp
-1, // deprecated
100, // JS code
2, // deprecated (symbol)
100, // JS code
1, // 32-bit int
8, // Mongo timestamp
1 // 64-bit int
][t];
},
// compare two values of unknown type according to BSON ordering
// semantics. (as an extension, consider 'undefined' to be less than
// any other value.) return negative if a is less, positive if b is
// less, or 0 if equal
_cmp: function _cmp(a, b) {
if (a === undefined) return b === undefined ? 0 : -1;
if (b === undefined) return 1;
var ta = this._type(a);
var tb = this._type(b);
var oa = this._typeorder(ta);
var ob = this._typeorder(tb);
if (oa !== ob) return oa < ob ? -1 : 1;
if (ta !== tb)
// XXX need to implement this if we implement Symbol or integers, or
// Timestamp
throw Error("Missing type coercion logic in _cmp");
if (ta === 7) {
// ObjectID
// Convert to string.
ta = tb = 2;
a = a.toHexString();
b = b.toHexString();
}
if (ta === 9) {
// Date
// Convert to millis.
ta = tb = 1;
a = a.getTime();
b = b.getTime();
}
if (ta === 1) // double
return a - b;
if (tb === 2) // string
return a < b ? -1 : a === b ? 0 : 1;
if (ta === 3) {
// Object
// this could be much more efficient in the expected case ...
var to_array = function to_array(obj) {
var ret = [];
for (var key in obj) {
ret.push(key);
ret.push(obj[key]);
}
return ret;
};
return this._cmp(to_array(a), to_array(b));
}
if (ta === 4) {
// Array
for (var i = 0;; i++) {
if (i === a.length) return i === b.length ? 0 : -1;
if (i === b.length) return 1;
var s = this._cmp(a[i], b[i]);
if (s !== 0) return s;
}
}
if (ta === 5) {
// binary
// Surprisingly, a small binary blob is always less than a large one in
// Mongo.
if (a.length !== b.length) return a.length - b.length;
for (i = 0; i < a.length; i++) {
if (a[i] < b[i]) return -1;
if (a[i] > b[i]) return 1;
}
return 0;
}
if (ta === 8) {
// boolean
if (a) return b ? 0 : 1;
return b ? -1 : 0;
}
if (ta === 10) // null
return 0;
if (ta === 11) // regexp
throw Error("Sorting not supported on regular expression"); // XXX
// 13: javascript code
// 14: symbol
// 15: javascript code with scope
// 16: 32-bit integer
// 17: timestamp
// 18: 64-bit integer
// 255: minkey
// 127: maxkey
if (ta === 13) // javascript code
throw Error("Sorting not supported on Javascript code"); // XXX
throw Error("Unknown type to sort");
}
};