Skip to content

Commit 7dfd293

Browse files
committed
add structIterator generator
1 parent 84c6d6c commit 7dfd293

File tree

7 files changed

+68
-12
lines changed

7 files changed

+68
-12
lines changed

.changeset/two-berries-repeat.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@smithy/smithy-client": minor
3+
---
4+
5+
add schema property to Command class

packages/core/src/submodules/cbor/CborCodec.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,18 @@ export class CborShapeSerializer implements ShapeSerializer {
5151
const ns = NormalizedSchema.of(schemaRef);
5252
const sparse = !!ns.getMergedTraits().sparse;
5353

54-
if (Array.isArray(_)) {
54+
if (ns.isListSchema() && Array.isArray(_)) {
5555
if (!sparse) {
5656
return _.filter((item) => item != null);
5757
}
5858
} else if (_ && typeof _ === "object") {
59-
if (!sparse || ns.isStructSchema()) {
59+
const members = ns.getMemberSchemas();
60+
const isStruct = ns.isStructSchema();
61+
if (!sparse || isStruct) {
6062
for (const [k, v] of Object.entries(_)) {
61-
if (v == null) {
63+
const filteredOutByNonSparse = !sparse && v == null;
64+
const filteredOutByUnrecognizedMember = isStruct && !(k in members);
65+
if (filteredOutByNonSparse || filteredOutByUnrecognizedMember) {
6266
delete _[k];
6367
}
6468
}
@@ -157,12 +161,8 @@ export class CborShapeDeserializer implements ShapeDeserializer {
157161
}
158162
}
159163
} else if (ns.isStructSchema()) {
160-
for (const key of Object.keys(value)) {
161-
const targetSchema = ns.getMemberSchema(key);
162-
if (targetSchema === undefined) {
163-
continue;
164-
}
165-
newObject[key] = this.readValue(targetSchema, value[key]);
164+
for (const [key, memberSchema] of ns.structIterator()) {
165+
newObject[key] = this.readValue(memberSchema, value[key]);
166166
}
167167
}
168168
return newObject;

packages/core/src/submodules/protocols/HttpProtocol.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export abstract class HttpProtocol implements ClientProtocol<IHttpRequest, IHttp
110110
if (operationNs.getMergedTraits().endpoint) {
111111
let hostPrefix = operationNs.getMergedTraits().endpoint?.[0];
112112
if (typeof hostPrefix === "string") {
113-
const hostLabelInputs = Object.entries(inputNs.getMemberSchemas()).filter(
113+
const hostLabelInputs = [...inputNs.structIterator()].filter(
114114
([, member]) => member.getMergedTraits().hostLabel
115115
);
116116
for (const [name] of hostLabelInputs) {
@@ -154,7 +154,7 @@ export abstract class HttpProtocol implements ClientProtocol<IHttpRequest, IHttp
154154
const ns = NormalizedSchema.of(schema);
155155
const nonHttpBindingMembers = [] as string[];
156156

157-
for (const [memberName, memberSchema] of Object.entries(ns.getMemberSchemas())) {
157+
for (const [memberName, memberSchema] of ns.structIterator()) {
158158
const memberTraits = memberSchema.getMemberTraits();
159159

160160
if (memberTraits.httpPayload) {

packages/core/src/submodules/schema/schemas/NormalizedSchema.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,20 @@ describe(NormalizedSchema.name, () => {
173173
});
174174
});
175175

176+
describe("iteration", () => {
177+
it("iterates over member schemas", () => {
178+
const iteration = Array.from(ns.structIterator());
179+
const entries = Object.entries(ns.getMemberSchemas());
180+
for (let i = 0; i < iteration.length; i++) {
181+
const [name, schema] = iteration[i];
182+
const [entryName, entrySchema] = entries[i];
183+
expect(name).toBe(entryName);
184+
expect(schema.getMemberName()).toEqual(entrySchema.getMemberName());
185+
expect(schema.getMergedTraits()).toEqual(entrySchema.getMergedTraits());
186+
}
187+
});
188+
});
189+
176190
describe("traits", () => {
177191
const member: MemberSchema = [sim("ack", "SimpleString", 0, { idempotencyToken: 1 }), 0b0000_0001];
178192
const ns = NormalizedSchema.of(member, "member_name");

packages/core/src/submodules/schema/schemas/NormalizedSchema.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,11 @@ export class NormalizedSchema implements INormalizedSchema {
371371
}
372372

373373
/**
374+
* This can be used for checking the members as a hashmap.
375+
* Prefer the structIterator method for iteration.
376+
*
377+
* This does NOT return list and map members, it is only for structures.
378+
*
374379
* @returns a map of member names to member schemas (normalized).
375380
*/
376381
public getMemberSchemas(): Record<string, NormalizedSchema> {
@@ -389,6 +394,22 @@ export class NormalizedSchema implements INormalizedSchema {
389394
return {};
390395
}
391396

397+
/**
398+
* Allows iteration over members of a structure schema.
399+
* Each yield is a pair of the member name and member schema.
400+
*
401+
* This avoids the overhead of calling Object.entries(ns.getMemberSchemas()).
402+
*/
403+
public *structIterator(): Generator<[string, NormalizedSchema], undefined, undefined> {
404+
if (!this.isStructSchema()) {
405+
throw new Error("@smithy/core/schema - cannot acquire structIterator on non-struct schema.");
406+
}
407+
const struct = this.getSchema() as StructureSchema;
408+
for (let i = 0; i < struct.memberNames.length; ++i) {
409+
yield [struct.memberNames[i], NormalizedSchema.memberFrom([struct.memberList[i], 0], struct.memberNames[i])];
410+
}
411+
}
412+
392413
/**
393414
* @returns a last-resort human-readable name for the schema if it has no other identifiers.
394415
*/

packages/core/src/submodules/serde/copyDocumentWithTransform.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const copyDocumentWithTransform = (
4545
newObject[key] = copyDocumentWithTransform(source[key], ns.getValueSchema(), transform);
4646
}
4747
} else if (ns.isStructSchema()) {
48-
for (const [key, memberSchema] of Object.entries(ns.getMemberSchemas())) {
48+
for (const [key, memberSchema] of ns.structIterator()) {
4949
newObject[key] = copyDocumentWithTransform(source[key], memberSchema, transform);
5050
}
5151
} else if (ns.isDocumentSchema()) {

packages/smithy-client/src/command.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import type {
1111
Logger,
1212
MetadataBearer,
1313
MiddlewareStack as IMiddlewareStack,
14+
Mutable,
15+
OperationSchema,
1416
OptionalParameter,
1517
Pluggable,
1618
RequestHandler,
@@ -31,6 +33,7 @@ export abstract class Command<
3133
{
3234
public abstract input: Input;
3335
public readonly middlewareStack: IMiddlewareStack<Input, Output> = constructStack<Input, Output>();
36+
public readonly schema?: OperationSchema;
3437

3538
/**
3639
* Factory for Command ClassBuilder.
@@ -131,6 +134,8 @@ class ClassBuilder<
131134
private _outputFilterSensitiveLog = (_: any) => _;
132135
private _serializer: (input: I, context: SerdeContext | any) => Promise<IHttpRequest> = null as any;
133136
private _deserializer: (output: IHttpResponse, context: SerdeContext | any) => Promise<O> = null as any;
137+
private _operationSchema?: OperationSchema;
138+
134139
/**
135140
* Optional init callback.
136141
*/
@@ -212,6 +217,16 @@ class ClassBuilder<
212217
this._deserializer = deserializer;
213218
return this;
214219
}
220+
221+
/**
222+
* Sets input/output schema for the operation.
223+
*/
224+
public sc(operation: OperationSchema): ClassBuilder<I, O, C, SI, SO> {
225+
this._operationSchema = operation;
226+
this._smithyContext.operationSchema = operation;
227+
return this;
228+
}
229+
215230
/**
216231
* @returns a Command class with the classBuilder properties.
217232
*/
@@ -241,6 +256,7 @@ class ClassBuilder<
241256
super();
242257
this.input = input ?? ({} as unknown as I);
243258
closure._init(this);
259+
(this as Mutable<typeof this>).schema = closure._operationSchema;
244260
}
245261

246262
/**

0 commit comments

Comments
 (0)