Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 26c695d

Browse files
committed
feat: Add sync DataConverter interface for workflow code
1 parent df31ade commit 26c695d

File tree

2 files changed

+126
-9
lines changed

2 files changed

+126
-9
lines changed

packages/common/src/converter/data-converter.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,32 @@ export interface DataConverter {
3838
* reason.
3939
*/
4040
fromPayloads<T>(index: number, content?: Payload[] | null): Promise<T>;
41+
42+
/**
43+
* Sync conversion of single payload, used in the Workflow runtime
44+
*/
45+
toPayloadSync<T>(value: T): Payload;
46+
47+
/**
48+
* Sync conversion from a single payload, used in the Workflow runtime
49+
*/
50+
fromPayloadSync<T>(payload: Payload): T;
51+
/**
52+
* Sync conversion of all arguments, used in the Workflow runtime
53+
*
54+
* Implements conversion of a list of values.
55+
*
56+
* @param values JS values to convert to Payloads.
57+
* @return converted value
58+
* @throws DataConverterError if conversion of the value passed as parameter failed for any
59+
* reason.
60+
*/
61+
toPayloadsSync(...values: unknown[]): Payload[] | undefined;
62+
63+
/**
64+
* Sync version of {@link fromPayloads}
65+
*/
66+
fromPayloadsSync<T>(index: number, content?: Payload[] | null): T;
4167
}
4268

4369
export class CompositeDataConverter implements DataConverter {
@@ -59,6 +85,14 @@ export class CompositeDataConverter implements DataConverter {
5985
throw new ValueError(`Cannot serialize ${value}`);
6086
}
6187

88+
public toPayloadSync<T>(value: T): Payload {
89+
for (const converter of this.converters) {
90+
const result = converter.toDataSync(value);
91+
if (result !== undefined) return result;
92+
}
93+
throw new ValueError(`Cannot serialize ${value}`);
94+
}
95+
6296
public async fromPayload<T>(payload: Payload): Promise<T> {
6397
if (payload.metadata === undefined || payload.metadata === null) {
6498
throw new ValueError('Missing payload metadata');
@@ -71,20 +105,47 @@ export class CompositeDataConverter implements DataConverter {
71105
return await converter.fromData(payload);
72106
}
73107

108+
public fromPayloadSync<T>(payload: Payload): T {
109+
if (payload.metadata === undefined || payload.metadata === null) {
110+
throw new ValueError('Missing payload metadata');
111+
}
112+
const encoding = str(payload.metadata[METADATA_ENCODING_KEY]);
113+
const converter = this.converterByEncoding.get(encoding);
114+
if (converter === undefined) {
115+
throw new ValueError(`Unknown encoding: ${encoding}`);
116+
}
117+
return converter.fromDataSync(payload);
118+
}
119+
74120
public async toPayloads(...values: unknown[]): Promise<Payload[] | undefined> {
75121
if (values.length === 0) {
76122
return undefined;
77123
}
78124
return await Promise.all(values.map((value) => this.toPayload(value)));
79125
}
80126

127+
public toPayloadsSync(...values: unknown[]): Payload[] | undefined {
128+
if (values.length === 0) {
129+
return undefined;
130+
}
131+
return values.map((value) => this.toPayloadSync(value));
132+
}
133+
81134
public async fromPayloads<T>(index: number, payloads?: Payload[] | null): Promise<T> {
82135
// To make adding arguments a backwards compatible change
83136
if (payloads === undefined || payloads === null || index >= payloads.length) {
84137
return undefined as any;
85138
}
86139
return await this.fromPayload(payloads[index]);
87140
}
141+
142+
public fromPayloadsSync<T>(index: number, payloads?: Payload[] | null): T {
143+
// To make adding arguments a backwards compatible change
144+
if (payloads === undefined || payloads === null || index >= payloads.length) {
145+
return undefined as any;
146+
}
147+
return this.fromPayloadSync(payloads[index]);
148+
}
88149
}
89150

90151
export async function arrayFromPayloads(converter: DataConverter, content?: Payload[] | null): Promise<unknown[]> {
@@ -105,6 +166,22 @@ export async function mapToPayloads<K extends string>(
105166
) as Record<K, Payload>;
106167
}
107168

169+
export function arrayFromPayloadsSync(converter: DataConverter, content?: Payload[] | null): unknown[] {
170+
if (!content) {
171+
return [];
172+
}
173+
return content.map((payload: Payload) => converter.fromPayloadSync(payload));
174+
}
175+
176+
export function mapToPayloadsSync<K extends string>(
177+
converter: DataConverter,
178+
source: Record<K, any>
179+
): Record<K, Payload> {
180+
return Object.fromEntries(
181+
Object.entries(source).map(([k, v]): [K, Payload] => [k as K, converter.toPayloadSync(v)])
182+
) as Record<K, Payload>;
183+
}
184+
108185
export const defaultDataConverter = new CompositeDataConverter(
109186
new UndefinedPayloadConverter(),
110187
new BinaryPayloadConverter(),

packages/common/src/converter/payload-converter.ts

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,55 @@ export interface PayloadConverter {
3030
* reason.
3131
*/
3232
fromData<T>(content: Payload): Promise<T>;
33+
34+
/**
35+
* Synchronous version of {@link toData}, used in the Workflow runtime because
36+
* the async version limits the functionality of the runtime.
37+
*
38+
* Implements conversion of value to payload
39+
*
40+
* @param value JS value to convert.
41+
* @return converted value
42+
* @throws DataConverterException if conversion of the value passed as parameter failed for any
43+
* reason.
44+
*/
45+
toDataSync(value: unknown): Payload | undefined;
46+
47+
/**
48+
* Synchronous version of {@link fromData}, used in the Workflow runtime because
49+
* the async version limits the functionality of the runtime.
50+
*
51+
* Implements conversion of payload to value.
52+
*
53+
* @param content Serialized value to convert to a JS value.
54+
* @return converted JS value
55+
* @throws DataConverterException if conversion of the data passed as parameter failed for any
56+
* reason.
57+
*/
58+
fromDataSync<T>(content: Payload): T;
59+
}
60+
61+
export abstract class AsyncFacadePayloadConverter implements PayloadConverter {
62+
abstract encodingType: string;
63+
abstract toDataSync(value: unknown): Payload | undefined;
64+
abstract fromDataSync<T>(content: Payload): T;
65+
66+
public async toData(value: unknown): Promise<Payload | undefined> {
67+
return this.toDataSync(value);
68+
}
69+
70+
public async fromData<T>(content: Payload): Promise<T> {
71+
return this.fromDataSync(content);
72+
}
3373
}
3474

3575
/**
3676
* Converts between JS undefined and NULL Payload
3777
*/
38-
export class UndefinedPayloadConverter implements PayloadConverter {
78+
export class UndefinedPayloadConverter extends AsyncFacadePayloadConverter {
3979
public encodingType = encodingTypes.METADATA_ENCODING_NULL;
4080

41-
public async toData(value: unknown): Promise<Payload | undefined> {
81+
public toDataSync(value: unknown): Payload | undefined {
4282
if (value !== undefined) return undefined; // Can't encode
4383
return {
4484
metadata: {
@@ -47,18 +87,18 @@ export class UndefinedPayloadConverter implements PayloadConverter {
4787
};
4888
}
4989

50-
public async fromData<T>(_content: Payload): Promise<T> {
90+
public fromDataSync<T>(_content: Payload): T {
5191
return undefined as any; // Just return undefined
5292
}
5393
}
5494

5595
/**
5696
* Converts between non-undefined values and serialized JSON Payload
5797
*/
58-
export class JsonPayloadConverter implements PayloadConverter {
98+
export class JsonPayloadConverter extends AsyncFacadePayloadConverter {
5999
public encodingType = encodingTypes.METADATA_ENCODING_JSON;
60100

61-
public async toData(value: unknown): Promise<Payload | undefined> {
101+
public toDataSync(value: unknown): Payload | undefined {
62102
if (value === undefined) return undefined; // Should be encoded with the UndefinedPayloadConverter
63103
return {
64104
metadata: {
@@ -68,7 +108,7 @@ export class JsonPayloadConverter implements PayloadConverter {
68108
};
69109
}
70110

71-
public async fromData<T>(content: Payload): Promise<T> {
111+
public fromDataSync<T>(content: Payload): T {
72112
if (content.data === undefined || content.data === null) {
73113
throw new ValueError('Got payload with no data');
74114
}
@@ -79,10 +119,10 @@ export class JsonPayloadConverter implements PayloadConverter {
79119
/**
80120
* Converts between binary data types and RAW Payload
81121
*/
82-
export class BinaryPayloadConverter implements PayloadConverter {
122+
export class BinaryPayloadConverter extends AsyncFacadePayloadConverter {
83123
public encodingType = encodingTypes.METADATA_ENCODING_RAW;
84124

85-
public async toData(value: unknown): Promise<Payload | undefined> {
125+
public toDataSync(value: unknown): Payload | undefined {
86126
// TODO: support any DataView or ArrayBuffer?
87127
if (!(value instanceof Uint8Array)) {
88128
return undefined;
@@ -95,7 +135,7 @@ export class BinaryPayloadConverter implements PayloadConverter {
95135
};
96136
}
97137

98-
public async fromData<T>(content: Payload): Promise<T> {
138+
public fromDataSync<T>(content: Payload): T {
99139
// TODO: support any DataView or ArrayBuffer?
100140
return content.data as any;
101141
}

0 commit comments

Comments
 (0)