-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathpayload-value-converter.ts
158 lines (143 loc) · 4.32 KB
/
payload-value-converter.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
/* Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. */
/* eslint-disable valid-jsdoc */
import BigNumber from 'bignumber.js';
import moment from 'moment';
import { identity } from 'rambda';
import { Time, EdmTypeShared } from '../common';
import {
deserializersCommon,
serializersCommom
} from '../common/payload-value-converter';
import { EdmTypeV4 } from './edm-types';
/**
* @hidden
*/
export function edmToTsV4<T extends EdmTypeV4>(
value: any,
edmType: EdmTypeShared<'v4'>
): EdmToPrimitiveV4<T> {
if (value === null || typeof value === 'undefined') {
return value;
}
if (deserializers[edmType]) {
return deserializers[edmType](value);
}
return value;
}
/**
* @hidden
*/
export function tsToEdmV4(value: any, edmType: EdmTypeShared<'v4'>): any {
if (value === null) {
return 'null';
}
if (serializers[edmType]) {
return serializers[edmType](value);
}
return value;
}
type EdmTypeMapping = {
[key in EdmTypeV4]: (value: any) => any;
};
function edmDateToMoment(date: string): moment.Moment {
const parsed = moment.utc(date, 'YYYY-MM-DD', true);
if (!parsed.isValid()) {
throw new Error(
`Provided date value ${date} does not follow the Edm.Date pattern: YYYY-MM-DD`
);
}
return parsed;
}
function edmDateTimeOffsetToMoment(dateTime: string): moment.Moment {
const prefix = 'YYYY-MM-DDTHH:mm';
// In moment the Z is either Offset from UTC as +-HH:mm, +-HHmm, or Z
const validFormats = [`${prefix}Z`, `${prefix}:ssZ`, `${prefix}:ss.SSSZ`];
const parsed = moment(dateTime, validFormats, true);
if (!parsed.isValid()) {
throw new Error(
`Provided date-time value ${dateTime} does not follow the Edm.DateTimeOffset pattern: YYYY-MM-DDTHH:mm(:ss(.SSS))Z`
);
}
return parsed;
}
function edmDurationToMoment(value: string): moment.Duration {
const durationPattern = /([\+,\-]{1,1})?P(\d{1,2}D)?(T(\d{1,2}H)?(\d{1,2}M)?(\d{1,2}S)?(\d{2,2}\.\d+S)?)?/;
const captured = durationPattern.exec(value);
if (!captured || captured[0] !== value) {
throw new Error(
`Provided duration value ${value} does not follow the Edm.Duration pattern: +/- P0DT0H0M0S`
);
}
return moment.duration(value);
}
function edmTimeOfDayToTime(value: string): Time {
const timeComponents = /(\d{2,2}):(\d{2,2}):(\d{2,2}(\.\d{1,12}){0,1})?/.exec(
value
);
if (!timeComponents) {
throw new Error(
`Provided time value ${value} does not follow the Edm.TimeOfDay pattern: HH:MM:SS(.S)`
);
}
return {
hours: parseInt(timeComponents[1]),
minutes: parseInt(timeComponents[2]),
seconds: parseFloat(timeComponents[3])
};
}
function momentToEdmDate(value: moment.Moment): string {
return value.format('YYYY-MM-DD');
}
function momentToEdmDateTimeOffsetToMoment(value: moment.Moment): string {
return value.utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z';
}
function durationToEdmDuration(value: moment.Duration): string {
return value.toISOString();
}
function timeToEdmTimeOfDay(value: Time): string {
return [value.hours, value.minutes, value.seconds]
.map(timeComponent => padTimeComponent(timeComponent))
.join(':');
}
function padTimeComponent(timeComponent: number): string {
const [wholeNumber, fractionalNumber] = timeComponent.toString().split('.');
return fractionalNumber
? [wholeNumber.padStart(2, '0'), fractionalNumber].join('.')
: wholeNumber.padStart(2, '0');
}
export type EdmToPrimitiveV4<T extends EdmTypeV4> = T extends
| 'Edm.Int16'
| 'Edm.Int32'
| 'Edm.Single'
| 'Edm.Double'
| 'Edm.Float'
| 'Edm.Byte'
| 'Edm.SByte'
? number
: T extends 'Edm.Decimal' | 'Edm.Int64'
? BigNumber
: T extends 'Edm.DateTime' | 'Edm.DateTimeOffset'
? moment.Moment
: T extends 'Edm.String' | 'Edm.Guid'
? string
: T extends 'Edm.Boolean'
? boolean
: T extends 'Edm.Time'
? Time
: any;
const deserializers: EdmTypeMapping = {
...deserializersCommon,
'Edm.Date': edmDateToMoment,
'Edm.DateTimeOffset': edmDateTimeOffsetToMoment,
'Edm.Duration': edmDurationToMoment,
'Edm.TimeOfDay': edmTimeOfDayToTime,
'Edm.Enum': identity
};
const serializers: EdmTypeMapping = {
...serializersCommom,
'Edm.Date': momentToEdmDate,
'Edm.DateTimeOffset': momentToEdmDateTimeOffsetToMoment,
'Edm.Duration': durationToEdmDuration,
'Edm.TimeOfDay': timeToEdmTimeOfDay,
'Edm.Enum': identity
};