name:
src/main/js/utils/Compare.ts
-rw-r--r--
4785
1import { ComparisonResult, comparisonResultFromNumber } from "../models/common/ComparisonResults";
2import { Converters } from "./Converters";
3import { isNull } from "../common/utils/Types";
4
5export class Compare {
6 /**
7 * Compare two objects using their type precedence first, and then defaulting to their default class compare methods
8 * if they are of the same type. If one is null, use a default depending on type.
9 *
10 * @param first - object to compare. Should be Double, Boolean, String, or null.
11 * @param second - second object to compare. Should be Double, Boolean, String, or null.
12 * @return ComparisonResult indicating less-than, greater-than, equal-to.
13 */
14 static compare(first: any, second: any): ComparisonResult {
15 const firstPrecedence = Compare.getTypePrecedence(first);
16 const secondPrecedence = Compare.getTypePrecedence(second);
17 if (firstPrecedence === secondPrecedence) {
18 if (isNull(first)) {
19 return ComparisonResult.EQUAL;
20 }
21 if (typeof first === "number") {
22 const firstNumber = Converters.toNumber(first);
23 const secondNumber = Converters.toNumber(second);
24 return comparisonResultFromNumber(Compare.numberComparison(firstNumber, secondNumber));
25 }
26 if (typeof first === "boolean") {
27 const firstBoolean = Converters.toBoolean(first);
28 const secondBoolean = Converters.toBoolean(second);
29 return comparisonResultFromNumber(Compare.booleanComparison(firstBoolean, secondBoolean));
30 }
31 if (typeof first === "string") {
32 const firstString = Converters.toText(first).toLowerCase();
33 const secondString = Converters.toText(second).toLowerCase();
34 return comparisonResultFromNumber(Compare.stringComparison(firstString, secondString));
35 }
36 }
37 // If the first is null, the second must be a number. First falls back to default.
38 if (isNull(first)) {
39 if (typeof second === "number") {
40 const firstNumber = 0;
41 const secondNumber = Converters.toNumber(second);
42 return comparisonResultFromNumber(Compare.numberComparison(firstNumber, secondNumber));
43 }
44 if (typeof second === "boolean") {
45 const firstBoolean = false;
46 const secondBoolean = Converters.toBoolean(second);
47 return comparisonResultFromNumber(Compare.booleanComparison(firstBoolean, secondBoolean));
48 }
49 if (typeof second === "string") {
50 const firstString = "";
51 const secondString = Converters.toText(second).toLowerCase();
52 return comparisonResultFromNumber(Compare.stringComparison(firstString, secondString));
53 }
54 }
55 // If the second is null, the first must be a number. Second falls back to default.
56 if (isNull(second)) {
57 if (typeof first === "number") {
58 const firstNumber = Converters.toNumber(first);
59 const secondNumber = 0;
60 return comparisonResultFromNumber(Compare.numberComparison(firstNumber, secondNumber));
61 }
62 if (typeof first === "boolean") {
63 const firstBoolean = Converters.toBoolean(first);
64 const secondBoolean = false;
65 return comparisonResultFromNumber(Compare.booleanComparison(firstBoolean, secondBoolean));
66 }
67 if (typeof first === "string") {
68 const firstString = Converters.toText(first).toLowerCase();
69 const secondString = "";
70 return comparisonResultFromNumber(Compare.stringComparison(firstString, secondString));
71 }
72 }
73 return comparisonResultFromNumber(Compare.numberComparison(firstPrecedence, secondPrecedence));
74 }
75
76 /**
77 * Strings, Numbers, and Booleans have type precedence that is used when comparing across types.
78 *
79 * @param value to get precedence of.
80 * @return {@code 1} if Number,{@code 2} if String, {@code 3} if Boolean.
81 */
82 static getTypePrecedence(value: any): number {
83 if (isNull(value)) {
84 return 0;
85 }
86 if (typeof value === "number") {
87 return 1;
88 }
89 if (typeof value === "string") {
90 return 2;
91 }
92 return 3;
93 }
94
95 /**
96 * Compare numbers by subtracting one from the other.
97 * @param first number
98 * @param second number
99 */
100 static numberComparison(first: number, second: number): number {
101 return first - second;
102 }
103
104 /**
105 * Compare boolean values, returning 0, 1, -1
106 * @param first boolean.
107 * @param second boolean.
108 */
109 static booleanComparison(first: boolean, second: boolean): number {
110 return (first ? 1 : 0) - (second ? 1 : 0);
111 }
112
113 /**
114 * Compare strings, returning 0, 1, -1;
115 * @param first
116 * @param second
117 */
118 static stringComparison(first: string, second: string): number {
119 if (first === second) {
120 return 0;
121 }
122 if (first > second) {
123 return 1;
124 }
125 return -1;
126 }
127}