Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 2s
185 lines
3.4 KiB
TypeScript
185 lines
3.4 KiB
TypeScript
import { BSONType } from './types';
|
|
|
|
export const getBSONType = <T>(v: T): BSONType => {
|
|
if (typeof v === 'number') {
|
|
return BSONType.Double;
|
|
}
|
|
|
|
if (typeof v === 'string') {
|
|
return BSONType.String;
|
|
}
|
|
|
|
if (typeof v === 'boolean') {
|
|
return BSONType.Boolean;
|
|
}
|
|
|
|
if (Array.isArray(v)) {
|
|
return BSONType.Array;
|
|
}
|
|
|
|
if (v === null) {
|
|
return BSONType.Null;
|
|
}
|
|
|
|
if (v instanceof RegExp) {
|
|
return BSONType.Regex;
|
|
}
|
|
|
|
if (typeof v === 'function') {
|
|
return BSONType.JavaScript;
|
|
}
|
|
|
|
if (v instanceof Date) {
|
|
return BSONType.Date;
|
|
}
|
|
|
|
if (v instanceof Uint8Array) {
|
|
return BSONType.BinData;
|
|
}
|
|
|
|
return BSONType.Object;
|
|
};
|
|
|
|
const getBSONTypeOrder = (type: BSONType): number => {
|
|
switch (type) {
|
|
case BSONType.Null:
|
|
return 0;
|
|
|
|
case BSONType.Double:
|
|
case BSONType.Int:
|
|
case BSONType.Long:
|
|
return 1;
|
|
|
|
case BSONType.String:
|
|
case BSONType.Symbol:
|
|
return 2;
|
|
|
|
case BSONType.Object:
|
|
return 3;
|
|
|
|
case BSONType.Array:
|
|
return 4;
|
|
|
|
case BSONType.BinData:
|
|
return 5;
|
|
|
|
case BSONType.ObjectId:
|
|
return 6;
|
|
|
|
case BSONType.Boolean:
|
|
return 7;
|
|
|
|
case BSONType.Date:
|
|
case BSONType.Timestamp:
|
|
return 8;
|
|
|
|
case BSONType.Regex:
|
|
return 9;
|
|
|
|
case BSONType.JavaScript:
|
|
case BSONType.JavaScriptWithScope:
|
|
return 100;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
};
|
|
|
|
type ObjectID = {
|
|
toHexString(): string;
|
|
equals(otherID: ObjectID): boolean;
|
|
};
|
|
|
|
export const compareBSONValues = (a: unknown, b: unknown): number => {
|
|
if (a === undefined) {
|
|
return b === undefined ? 0 : -1;
|
|
}
|
|
|
|
if (b === undefined) {
|
|
return 1;
|
|
}
|
|
|
|
const ta = getBSONType(a);
|
|
const oa = getBSONTypeOrder(ta);
|
|
|
|
const tb = getBSONType(b);
|
|
const ob = getBSONTypeOrder(tb);
|
|
|
|
if (oa !== ob) {
|
|
return oa < ob ? -1 : 1;
|
|
}
|
|
|
|
if (ta !== tb) {
|
|
throw Error('Missing type coercion logic in compareBSONValues');
|
|
}
|
|
|
|
switch (ta) {
|
|
case BSONType.Double:
|
|
return (a as number) - (b as number);
|
|
|
|
case BSONType.String:
|
|
return (a as string).localeCompare(b as string);
|
|
|
|
case BSONType.Object:
|
|
return compareBSONValues(
|
|
Array.prototype.concat.call([], ...Object.entries(a as Record<string, unknown>)),
|
|
Array.prototype.concat.call([], ...Object.entries(b as Record<string, unknown>)),
|
|
);
|
|
|
|
case BSONType.Array: {
|
|
for (let i = 0; ; i++) {
|
|
if (i === (a as unknown[]).length) {
|
|
return i === (b as unknown[]).length ? 0 : -1;
|
|
}
|
|
|
|
if (i === (b as unknown[]).length) {
|
|
return 1;
|
|
}
|
|
|
|
const s = compareBSONValues((a as unknown[])[i], (b as unknown[])[i]);
|
|
if (s !== 0) {
|
|
return s;
|
|
}
|
|
}
|
|
}
|
|
|
|
case BSONType.BinData: {
|
|
if ((a as Uint8Array).length !== (b as Uint8Array).length) {
|
|
return (a as Uint8Array).length - (b as Uint8Array).length;
|
|
}
|
|
|
|
for (let i = 0; i < (a as Uint8Array).length; i++) {
|
|
if ((a as Uint8Array)[i] === (b as Uint8Array)[i]) {
|
|
continue;
|
|
}
|
|
|
|
return (a as Uint8Array)[i] < (b as Uint8Array)[i] ? -1 : 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
case BSONType.Null:
|
|
case BSONType.Undefined:
|
|
return 0;
|
|
|
|
case BSONType.ObjectId:
|
|
return (a as ObjectID).toHexString().localeCompare((b as ObjectID).toHexString());
|
|
|
|
case BSONType.Boolean:
|
|
return Number(a) - Number(b);
|
|
|
|
case BSONType.Date:
|
|
return (a as Date).getTime() - (b as Date).getTime();
|
|
|
|
case BSONType.Regex:
|
|
throw Error('Sorting not supported on regular expression');
|
|
|
|
case BSONType.JavaScript:
|
|
case BSONType.JavaScriptWithScope:
|
|
throw Error('Sorting not supported on Javascript code');
|
|
}
|
|
|
|
throw Error('Unknown type to sort');
|
|
};
|