Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/pink-items-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@smithy/types": minor
"@smithy/core": minor
---

schema code size optimizations
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe(HttpBindingProtocol.name, () => {
const response = new HttpResponse({
statusCode: 200,
headers: {
"x-timestamplist": "Mon, 16 Dec 2019 23:48:18 GMT, Mon, 16 Dec 2019 23:48:18 GMT",
"x-timestamplist": "Mon, 16 Nov 2019 23:48:18 GMT, Mon, 16 Dec 2019 23:48:18 GMT",
},
});

Expand Down Expand Up @@ -95,7 +95,7 @@ describe(HttpBindingProtocol.name, () => {
)) as Partial<MetadataBearer>;
delete output.$metadata;
expect(output).toEqual({
timestampList: [new Date("2019-12-16T23:48:18.000Z"), new Date("2019-12-16T23:48:18.000Z")],
timestampList: [new Date("2019-11-16T23:48:18.000Z"), new Date("2019-12-16T23:48:18.000Z")],
});
});

Expand Down
30 changes: 14 additions & 16 deletions packages/core/src/submodules/protocols/HttpBindingProtocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,20 +157,15 @@ export abstract class HttpBindingProtocol extends HttpProtocol {
if (traits.httpQueryParams) {
for (const [key, val] of Object.entries(data)) {
if (!(key in query)) {
this.serializeQuery(
NormalizedSchema.of([
ns.getValueSchema(),
{
// We pass on the traits to the sub-schema
// because we are still in the process of serializing the map itself.
...traits,
httpQuery: key,
httpQueryParams: undefined,
},
]),
val,
query
);
const valueSchema = ns.getValueSchema();
Object.assign(valueSchema.getMergedTraits(), {
// We pass on the traits to the sub-schema
// because we are still in the process of serializing the map itself.
...traits,
httpQuery: key,
httpQueryParams: undefined,
});
this.serializeQuery(valueSchema, val, query);
}
}
return;
Expand Down Expand Up @@ -305,6 +300,7 @@ export abstract class HttpBindingProtocol extends HttpProtocol {
if (null != value) {
if (memberSchema.isListSchema()) {
const headerListValueSchema = memberSchema.getValueSchema();
headerListValueSchema.getMergedTraits().httpHeader = key;
let sections: string[];
if (
headerListValueSchema.isTimestampSchema() &&
Expand All @@ -316,7 +312,7 @@ export abstract class HttpBindingProtocol extends HttpProtocol {
}
const list = [];
for (const section of sections) {
list.push(await deserializer.read([headerListValueSchema, { httpHeader: key }], section.trim()));
list.push(await deserializer.read(headerListValueSchema, section.trim()));
}
dataObject[memberName] = list;
} else {
Expand All @@ -327,8 +323,10 @@ export abstract class HttpBindingProtocol extends HttpProtocol {
dataObject[memberName] = {};
for (const [header, value] of Object.entries(response.headers)) {
if (header.startsWith(memberTraits.httpPrefixHeaders)) {
const valueSchema = memberSchema.getValueSchema();
valueSchema.getMergedTraits().httpHeader = header;
dataObject[memberName][header.slice(memberTraits.httpPrefixHeaders.length)] = await deserializer.read(
[memberSchema.getValueSchema(), { httpHeader: header }],
valueSchema,
value
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,18 @@ export class FromStringShapeDeserializer implements ShapeDeserializer<string> {

public read(_schema: Schema, data: string): any {
const ns = NormalizedSchema.of(_schema);

if (ns.isListSchema()) {
return splitHeader(data).map((item) => this.read(ns.getValueSchema(), item));
}

if (ns.isBlobSchema()) {
return (this.serdeContext?.base64Decoder ?? fromBase64)(data);
}

if (ns.isTimestampSchema()) {
const format = determineTimestampFormat(ns, this.settings);

switch (format) {
case SCHEMA.TIMESTAMP_DATE_TIME:
return parseRfc3339DateTimeWithOffset(data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export function determineTimestampFormat(
}

const { httpLabel, httpPrefixHeaders, httpHeader, httpQuery } = ns.getMergedTraits();

const bindingFormat = settings.httpBindings
? typeof httpPrefixHeaders === "string" || Boolean(httpHeader)
? SCHEMA.TIMESTAMP_HTTP_DATE
Expand Down
46 changes: 15 additions & 31 deletions packages/core/src/submodules/schema/schemas/ErrorSchema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { SchemaRef, SchemaTraits } from "@smithy/types";

import { TypeRegistry } from "../TypeRegistry";
import { Schema } from "./Schema";
import { StructureSchema } from "./StructureSchema";

/**
Expand All @@ -12,30 +13,9 @@ import { StructureSchema } from "./StructureSchema";
* @alpha
*/
export class ErrorSchema extends StructureSchema {
public static symbol = Symbol.for("@smithy/core/schema::ErrorSchema");
protected symbol = ErrorSchema.symbol;

public constructor(
public name: string,
public traits: SchemaTraits,
public memberNames: string[],
public memberList: SchemaRef[],
/**
* Constructor for a modeled service exception class that extends Error.
*/
public ctor: any
) {
super(name, traits, memberNames, memberList);
}

public static [Symbol.hasInstance](lhs: unknown): lhs is ErrorSchema {
const isPrototype = ErrorSchema.prototype.isPrototypeOf(lhs as any);
if (!isPrototype && typeof lhs === "object" && lhs !== null) {
const err = lhs as ErrorSchema;
return err.symbol === ErrorSchema.symbol;
}
return isPrototype;
}
public static readonly symbol = Symbol.for("@smithy/err");
public ctor!: any;
protected readonly symbol = ErrorSchema.symbol;
}

/**
Expand All @@ -50,15 +30,19 @@ export class ErrorSchema extends StructureSchema {
* @param memberList - list of schemaRef corresponding to each
* @param ctor - class reference for the existing Error extending class.
*/
export function error(
export const error = (
namespace: string,
name: string,
traits: SchemaTraits = {},
traits: SchemaTraits,
memberNames: string[],
memberList: SchemaRef[],
ctor: any
): ErrorSchema {
const schema = new ErrorSchema(namespace + "#" + name, traits, memberNames, memberList, ctor);
TypeRegistry.for(namespace).register(name, schema);
return schema;
}
): ErrorSchema =>
Schema.assign(new ErrorSchema(), {
name,
namespace,
traits,
memberNames,
memberList,
ctor,
});
39 changes: 11 additions & 28 deletions packages/core/src/submodules/schema/schemas/ListSchema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { ListSchema as IListSchema, SchemaRef, SchemaTraits } from "@smithy/types";

import { TypeRegistry } from "../TypeRegistry";
import { Schema } from "./Schema";

/**
Expand All @@ -10,38 +9,22 @@ import { Schema } from "./Schema";
* @alpha
*/
export class ListSchema extends Schema implements IListSchema {
public static symbol = Symbol.for("@smithy/core/schema::ListSchema");
protected symbol = ListSchema.symbol;

public constructor(
public name: string,
public traits: SchemaTraits,
public valueSchema: SchemaRef
) {
super(name, traits);
}

public static [Symbol.hasInstance](lhs: unknown): lhs is ListSchema {
const isPrototype = ListSchema.prototype.isPrototypeOf(lhs as any);
if (!isPrototype && typeof lhs === "object" && lhs !== null) {
const list = lhs as ListSchema;
return list.symbol === ListSchema.symbol;
}
return isPrototype;
}
public static readonly symbol = Symbol.for("@smithy/lis");
public name!: string;
public traits!: SchemaTraits;
public valueSchema!: SchemaRef;
protected readonly symbol = ListSchema.symbol;
}

/**
* Factory for ListSchema.
*
* @internal
*/
export function list(namespace: string, name: string, traits: SchemaTraits = {}, valueSchema: SchemaRef): ListSchema {
const schema = new ListSchema(
namespace + "#" + name,
export const list = (namespace: string, name: string, traits: SchemaTraits, valueSchema: SchemaRef): ListSchema =>
Schema.assign(new ListSchema(), {
name,
namespace,
traits,
typeof valueSchema === "function" ? valueSchema() : valueSchema
);
TypeRegistry.for(namespace).register(name, schema);
return schema;
}
valueSchema,
});
51 changes: 17 additions & 34 deletions packages/core/src/submodules/schema/schemas/MapSchema.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,38 @@
import type { MapSchema as IMapSchema, SchemaRef, SchemaTraits } from "@smithy/types";

import { TypeRegistry } from "../TypeRegistry";
import { Schema } from "./Schema";

/**
* A schema with a key schema and value schema.
* @alpha
*/
export class MapSchema extends Schema implements IMapSchema {
public static symbol = Symbol.for("@smithy/core/schema::MapSchema");
protected symbol = MapSchema.symbol;

public constructor(
public name: string,
public traits: SchemaTraits,
/**
* This is expected to be StringSchema, but may have traits.
*/
public keySchema: SchemaRef,
public valueSchema: SchemaRef
) {
super(name, traits);
}

public static [Symbol.hasInstance](lhs: unknown): lhs is MapSchema {
const isPrototype = MapSchema.prototype.isPrototypeOf(lhs as any);
if (!isPrototype && typeof lhs === "object" && lhs !== null) {
const map = lhs as MapSchema;
return map.symbol === MapSchema.symbol;
}
return isPrototype;
}
public static readonly symbol = Symbol.for("@smithy/map");
public name!: string;
public traits!: SchemaTraits;
/**
* This is expected to be StringSchema, but may have traits.
*/
public keySchema!: SchemaRef;
public valueSchema!: SchemaRef;
protected readonly symbol = MapSchema.symbol;
}

/**
* Factory for MapSchema.
* @internal
*/
export function map(
export const map = (
namespace: string,
name: string,
traits: SchemaTraits = {},
traits: SchemaTraits,
keySchema: SchemaRef,
valueSchema: SchemaRef
): MapSchema {
const schema = new MapSchema(
namespace + "#" + name,
): MapSchema =>
Schema.assign(new MapSchema(), {
name,
namespace,
traits,
keySchema,
typeof valueSchema === "function" ? valueSchema() : valueSchema
);
TypeRegistry.for(namespace).register(name, schema);
return schema;
}
valueSchema,
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { MemberSchema } from "@smithy/types";
import type { MemberSchema, StructureSchema } from "@smithy/types";
import { describe, expect, test as it } from "vitest";

import { list } from "./ListSchema";
Expand All @@ -12,8 +12,8 @@ describe(NormalizedSchema.name, () => {
const [List, Map, Struct] = [list("ack", "List", { sparse: 1 }, 0), map("ack", "Map", 0, 0, 1), () => schema];
const schema = struct("ack", "Structure", {}, ["list", "map", "struct"], [List, Map, Struct]);

const ns = new NormalizedSchema(() => schema);
const nsFromIndirect = NormalizedSchema.of([() => ns, 0]);
const ns = NormalizedSchema.of(schema);
const nsFromIndirect = NormalizedSchema.of(() => ns);

it("has a static constructor", () => {
expect(NormalizedSchema.of(ns)).toBeInstanceOf(NormalizedSchema);
Expand Down Expand Up @@ -105,7 +105,15 @@ describe(NormalizedSchema.name, () => {
expect(NormalizedSchema.of(SCHEMA.BIG_INTEGER).isBigIntegerSchema()).toBe(true);
expect(NormalizedSchema.of(SCHEMA.BIG_DECIMAL).isBigDecimalSchema()).toBe(true);
expect(NormalizedSchema.of(SCHEMA.STREAMING_BLOB).isStreaming()).toBe(true);
expect(NormalizedSchema.of([ns, { streaming: 1 }]).isStreaming()).toBe(true);

const structWithStreamingMember = struct(
"ack",
"StructWithStreamingMember",
0,
["m"],
[sim("ns", "blob", SCHEMA.BLOB, { streaming: 1 })]
);
expect(NormalizedSchema.of(structWithStreamingMember).getMemberSchema("m").isStreaming()).toBe(true);
});

describe("list member", () => {
Expand Down Expand Up @@ -184,8 +192,8 @@ describe(NormalizedSchema.name, () => {

describe("iteration", () => {
it("iterates over member schemas", () => {
const iteration = Array.from(ns.structIterator());
const entries = Object.entries(ns.getMemberSchemas());
const iteration = Array.from(ns.structIterator()) as [string, NormalizedSchema][];
const entries = Object.entries(ns.getMemberSchemas()) as [string, NormalizedSchema][];
for (let i = 0; i < iteration.length; i++) {
const [name, schema] = iteration[i];
const [entryName, entrySchema] = entries[i];
Expand All @@ -203,7 +211,9 @@ describe(NormalizedSchema.name, () => {

describe("traits", () => {
const member: MemberSchema = [sim("ack", "SimpleString", 0, { idempotencyToken: 1 }), 0b0000_0001];
const ns = NormalizedSchema.of(member, "member_name");
const container: StructureSchema = struct("ack", "Container", 0, ["member_name"], [member, 0]);

const ns = NormalizedSchema.of(container).getMemberSchema("member_name");

it("has merged traits", () => {
expect(ns.getMergedTraits()).toEqual({
Expand Down
Loading
Loading