-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: breakup serializeHelpers and deserializeHelpers into indivi…
…dual files
- Loading branch information
Ashwin Kumar
committed
Sep 23, 2024
1 parent
f0acfc2
commit 9e015a8
Showing
18 changed files
with
349 additions
and
305 deletions.
There are no files selected for viewing
27 changes: 27 additions & 0 deletions
27
...ge/src/foundation/factories/serviceClients/s3/deserialization/buildStorageServiceError.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
import { ServiceError } from '@aws-amplify/core/internals/utils'; | ||
|
||
import { StorageError } from '../../../../../errors/StorageError'; | ||
|
||
/** | ||
* Internal-only method to create a new StorageError from a service error. | ||
* | ||
* @internal | ||
*/ | ||
export const buildStorageServiceError = ( | ||
error: Error, | ||
statusCode: number, | ||
): ServiceError => { | ||
const storageError = new StorageError({ | ||
name: error.name, | ||
message: error.message, | ||
}); | ||
if (statusCode === 404) { | ||
storageError.recoverySuggestion = | ||
'Please add the object with this key to the bucket as the key is not found.'; | ||
} | ||
|
||
return storageError; | ||
}; |
45 changes: 45 additions & 0 deletions
45
...rc/foundation/factories/serviceClients/s3/deserialization/createStringEnumDeserializer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
import { StorageError } from '../../../../../errors/StorageError'; | ||
|
||
/** | ||
* Create a function deserializing a string to an enum value. If the string is not a valid enum value, it throws a | ||
* StorageError. | ||
* | ||
* @example | ||
* ```typescript | ||
* const deserializeStringEnum = createStringEnumDeserializer(['a', 'b', 'c'] as const, 'FieldName'); | ||
* const deserializedArray = ['a', 'b', 'c'].map(deserializeStringEnum); | ||
* // deserializedArray = ['a', 'b', 'c'] | ||
* | ||
* const invalidValue = deserializeStringEnum('d'); | ||
* // Throws InvalidFieldName: Invalid FieldName: d | ||
* ``` | ||
* | ||
* @internal | ||
*/ | ||
export const createStringEnumDeserializer = <T extends readonly string[]>( | ||
enumValues: T, | ||
fieldName: string, | ||
) => { | ||
const deserializeStringEnum = ( | ||
value: any, | ||
): T extends (infer E)[] ? E : never => { | ||
const parsedEnumValue = value | ||
? (enumValues.find(enumValue => enumValue === value) as any) | ||
: undefined; | ||
if (!parsedEnumValue) { | ||
throw new StorageError({ | ||
name: `Invalid${fieldName}`, | ||
message: `Invalid ${fieldName}: ${value}`, | ||
recoverySuggestion: | ||
'This is likely to be a bug. Please reach out to library authors.', | ||
}); | ||
} | ||
|
||
return parsedEnumValue; | ||
}; | ||
|
||
return deserializeStringEnum; | ||
}; |
12 changes: 12 additions & 0 deletions
12
.../storage/src/foundation/factories/serviceClients/s3/deserialization/deserializeBoolean.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
/** | ||
* Deserializes a string to a boolean. Returns undefined if input is undefined. Returns true if input is 'true', | ||
* otherwise false. | ||
* | ||
* @internal | ||
*/ | ||
export const deserializeBoolean = (value?: string): boolean | undefined => { | ||
return value ? value === 'true' : undefined; | ||
}; |
22 changes: 22 additions & 0 deletions
22
...storage/src/foundation/factories/serviceClients/s3/deserialization/deserializeMetadata.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
import { Headers } from '@aws-amplify/core/internals/aws-client-utils'; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export const deserializeMetadata = ( | ||
headers: Headers, | ||
): Record<string, string> => { | ||
const objectMetadataHeaderPrefix = 'x-amz-meta-'; | ||
const deserialized = Object.keys(headers) | ||
.filter(header => header.startsWith(objectMetadataHeaderPrefix)) | ||
.reduce((acc, header) => { | ||
acc[header.replace(objectMetadataHeaderPrefix, '')] = headers[header]; | ||
|
||
return acc; | ||
}, {} as any); | ||
|
||
return Object.keys(deserialized).length > 0 ? deserialized : undefined; | ||
}; |
10 changes: 10 additions & 0 deletions
10
...s/storage/src/foundation/factories/serviceClients/s3/deserialization/deserializeNumber.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
/** | ||
* Deserializes a string to a number. Returns undefined if input is undefined. | ||
* | ||
* @internal | ||
*/ | ||
export const deserializeNumber = (value?: string): number | undefined => | ||
value ? Number(value) : undefined; |
19 changes: 19 additions & 0 deletions
19
...torage/src/foundation/factories/serviceClients/s3/deserialization/deserializeTimestamp.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
/** | ||
* Deserializes a string to a Date. Returns undefined if input is undefined. | ||
* It supports epoch timestamp; rfc3339(cannot have a UTC, fractional precision supported); rfc7231(section 7.1.1.1) | ||
* | ||
* @see https://www.epoch101.com/ | ||
* @see https://datatracker.ietf.org/doc/html/rfc3339.html#section-5.6 | ||
* @see https://datatracker.ietf.org/doc/html/rfc7231.html#section-7.1.1.1 | ||
* | ||
* @note For bundle size consideration, we use Date constructor to parse the timestamp string. There might be slight | ||
* difference among browsers. | ||
* | ||
* @internal | ||
*/ | ||
export const deserializeTimestamp = (value: string): Date | undefined => { | ||
return value ? new Date(value) : undefined; | ||
}; |
21 changes: 21 additions & 0 deletions
21
...ges/storage/src/foundation/factories/serviceClients/s3/deserialization/emptyArrayGuard.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
/** | ||
* Function that makes sure the deserializer receives non-empty array. | ||
* | ||
* @internal | ||
*/ | ||
export const emptyArrayGuard = <T extends any[]>( | ||
value: any, | ||
deserializer: (value: any[]) => T, | ||
): T => { | ||
if (value === '') { | ||
return [] as any as T; | ||
} | ||
const valueArray = (Array.isArray(value) ? value : [value]).filter( | ||
e => e != null, | ||
); | ||
|
||
return deserializer(valueArray); | ||
}; |
12 changes: 12 additions & 0 deletions
12
packages/storage/src/foundation/factories/serviceClients/s3/deserialization/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// TODO(ashwinkumar6): remove duplicate storage/src/providers/s3/utils/client/utils/deserializeHelpers.ts | ||
export { buildStorageServiceError } from './buildStorageServiceError'; | ||
export { createStringEnumDeserializer } from './createStringEnumDeserializer'; | ||
export { deserializeBoolean } from './deserializeBoolean'; | ||
export { deserializeMetadata } from './deserializeMetadata'; | ||
export { deserializeNumber } from './deserializeNumber'; | ||
export { deserializeTimestamp } from './deserializeTimestamp'; | ||
export { emptyArrayGuard } from './emptyArrayGuard'; | ||
export { map } from './map'; |
67 changes: 67 additions & 0 deletions
67
packages/storage/src/foundation/factories/serviceClients/s3/deserialization/map.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
type PropertyNameWithStringValue = string; | ||
|
||
type PropertyNameWithSubsequentDeserializer<T> = [string, (arg: any) => T]; | ||
|
||
type Instruction<T> = | ||
| PropertyNameWithStringValue | ||
| PropertyNameWithSubsequentDeserializer<T>; | ||
|
||
type InferInstructionResultType<T extends Instruction<any>> = | ||
| (T extends PropertyNameWithSubsequentDeserializer<infer R> ? R : string) | ||
| never; | ||
|
||
/** | ||
* Maps an object to a new object using the provided instructions. | ||
* The instructions are a map of the returning mapped object's property names to a single instruction of how to map the | ||
* value from the original object to the new object. There are two types of instructions: | ||
* | ||
* 1. A string representing the property name of the original object to map to the new object. The value mapped from | ||
* the original object will be the same as the value in the new object, and it can ONLY be string. | ||
* | ||
* 2. An array of two elements. The first element is the property name of the original object to map to the new object. | ||
* The second element is a function that takes the value from the original object and returns the value to be mapped to | ||
* the new object. The function can return any type. | ||
* | ||
* Example: | ||
* ```typescript | ||
* const input = { | ||
* Foo: 'foo', | ||
* BarList: [{value: 'bar1'}, {value: 'bar2'}] | ||
* } | ||
* const output = map(input, { | ||
* someFoo: 'Foo', | ||
* bar: ['BarList', (barList) => barList.map(bar => bar.value)] | ||
* baz: 'Baz' // Baz does not exist in input, so it will not be in the output. | ||
* }); | ||
* // output = { someFoo: 'foo', bar: ['bar1', 'bar2'] } | ||
* ``` | ||
* | ||
* @param obj The object containing the data to compose mapped object. | ||
* @param instructions The instructions mapping the object values to the new object. | ||
* @returns A new object with the mapped values. | ||
* | ||
* @internal | ||
*/ | ||
export const map = <Instructions extends Record<string, Instruction<any>>>( | ||
obj: Record<string, any>, | ||
instructions: Instructions, | ||
): { | ||
[K in keyof Instructions]: InferInstructionResultType<Instructions[K]>; | ||
} => { | ||
const result = {} as Record<keyof Instructions, any>; | ||
for (const [key, instruction] of Object.entries(instructions)) { | ||
const [accessor, deserializer] = Array.isArray(instruction) | ||
? instruction | ||
: [instruction]; | ||
if (Object.prototype.hasOwnProperty.call(obj, accessor)) { | ||
result[key as keyof Instructions] = deserializer | ||
? deserializer(obj[accessor]) | ||
: String(obj[accessor]); | ||
} | ||
} | ||
|
||
return result; | ||
}; |
Oops, something went wrong.