-
Notifications
You must be signed in to change notification settings - Fork 48
/
Null.ts
187 lines (163 loc) · 5.43 KB
/
Null.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import { Decimal, IonType, IonTypes, Writer } from "../Ion";
import { FromJsConstructor } from "./FromJsConstructor";
import { PathElement, Value } from "./Value";
/**
* Represents a null[1] value in an Ion stream.
*
* An Ion null differs from a Javascript null in that an instance of an Ion null may have data associated with it.
*
* In particular, Ion nulls have an Ion data type:
*
* text encoding | Ion data type
* ======================================
* null | IonType.NULL
* null.null | IonType.NULL
* null.string | IonType.STRING
* null.int | IonType.INT
* null.struct | IonType.STRUCT
* ...
*
* They can also be annotated:
*
* customerName::null.string
* dollars::null.decimal
* meters::null.float
*
* [1] https://amazon-ion.github.io/ion-docs/docs/spec.html#null
*/
export class Null extends Value(Object, IonTypes.NULL, FromJsConstructor.NONE) {
private static _supportedIonTypesByOperation = new Map<string, Set<IonType>>([
["booleanValue", new Set([IonTypes.BOOL])],
["numberValue", new Set([IonTypes.INT, IonTypes.FLOAT, IonTypes.DECIMAL])],
["bigIntValue", new Set([IonTypes.INT])],
["decimalValue", new Set([IonTypes.DECIMAL])],
["stringValue", new Set([IonTypes.STRING, IonTypes.SYMBOL])],
["dateValue", new Set([IonTypes.TIMESTAMP])],
["timestampValue", new Set([IonTypes.TIMESTAMP])],
["uInt8ArrayValue", new Set([IonTypes.BLOB, IonTypes.CLOB])],
["fields", new Set([IonTypes.STRUCT])],
["fieldNames", new Set([IonTypes.STRUCT])],
["elements", new Set([IonTypes.LIST, IonTypes.SEXP, IonTypes.STRUCT])],
]);
private static _operationIsSupported(
ionType: IonType,
operation: string
): boolean {
return Null._supportedIonTypesByOperation.get(operation)!.has(ionType);
}
/**
* Constructor.
* @param ionType The Ion data type associated with this null value.
* @param annotations An optional array of strings to associate with this null value.
*/
constructor(ionType: IonType = IonTypes.NULL, annotations: string[] = []) {
super();
this._ionType = ionType;
this._setAnnotations(annotations);
}
isNull(): boolean {
return true;
}
// If a [type]Value() operation was called on this Null value, we need to see whether the associated Ion type
// supports that conversion. If it does, we'll return a JS null. If it doesn't, we'll throw an Error.
private _convertToJsNull(operation: string): null | never {
if (Null._operationIsSupported(this.getType(), operation)) {
return null;
}
throw new Error(
`${operation}() is not supported by Ion type ${this.getType().name}`
);
}
// If this Null's Ion type supports the requested operation, throw an Error indicating this was a null dereference.
// Otherwise, throw an Error indicating that the requested operation is not supported.
private _unsupportedOperationOrNullDereference(operation: string): never {
if (Null._operationIsSupported(this.getType(), operation)) {
throw new Error(
`${operation}() called on a null ${this.getType().name}.`
);
}
throw new Error(
`${operation}() is not supported by Ion type ${this.getType().name}`
);
}
booleanValue(): boolean | null {
return this._convertToJsNull("booleanValue");
}
numberValue(): number | null {
return this._convertToJsNull("numberValue");
}
bigIntValue(): bigint | null {
return this._convertToJsNull("bigIntValue");
}
decimalValue(): Decimal | null {
return this._convertToJsNull("decimalValue");
}
stringValue(): string | null {
return this._convertToJsNull("stringValue");
}
dateValue(): Date | null {
return this._convertToJsNull("dateValue");
}
uInt8ArrayValue(): Uint8Array | null {
return this._convertToJsNull("uInt8ArrayValue");
}
fieldNames(): string[] {
this._unsupportedOperationOrNullDereference("fieldNames");
}
fields(): [string, Value][] {
this._unsupportedOperationOrNullDereference("fields");
}
elements(): Value[] {
this._unsupportedOperationOrNullDereference("elements");
}
get(...pathElements: PathElement[]): Value | null {
return null;
}
toString(): string {
if (this.getType() == IonTypes.NULL) {
return "null";
}
return "null." + this._ionType.name;
}
/**
* Converts this dom.Null to a Javascript null when being serialized with `JSON.stringify()`.
*/
toJSON() {
return null;
}
writeTo(writer: Writer): void {
writer.setAnnotations(this.getAnnotations());
writer.writeNull(this.getType());
}
_valueEquals(
other: any,
options: {
epsilon?: number | null;
ignoreAnnotations?: boolean;
ignoreTimestampPrecision?: boolean;
onlyCompareIon?: boolean;
} = {
epsilon: null,
ignoreAnnotations: false,
ignoreTimestampPrecision: false,
onlyCompareIon: true,
}
): boolean {
let isSupportedType: boolean = false;
let valueToCompare: any = null;
// if the provided value is an ion.dom.Null instance.
if (other instanceof Null) {
isSupportedType = true;
valueToCompare = other;
} else if (!options.onlyCompareIon) {
// We will consider other Null-ish types
if (other === null && this._ionType.name === "null") {
return true;
}
}
if (!isSupportedType) {
return false;
}
return this._ionType.name === valueToCompare._ionType.name;
}
}