Skip to content

Commit f679066

Browse files
committed
Add some test cases, fix error
1 parent 60afb6a commit f679066

File tree

5 files changed

+103
-8
lines changed

5 files changed

+103
-8
lines changed

packages/vertexai/src/errors.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ export class VertexAIError extends FirebaseError {
3333
* @param customErrorData - Optional error data.
3434
*/
3535
constructor(
36-
readonly code: VertexAIErrorCode,
37-
readonly message: string,
36+
code: VertexAIErrorCode,
37+
message: string,
3838
readonly customErrorData?: CustomErrorData
3939
) {
4040
// Match error format used by FirebaseError from ErrorFactory

packages/vertexai/src/requests/schema-builder.test.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import { expect, use } from 'chai';
1919
import sinonChai from 'sinon-chai';
2020
import { Schema } from './schema-builder';
21+
import { VertexAIErrorCode } from '../types';
2122

2223
use(sinonChai);
2324

@@ -29,13 +30,30 @@ describe.only('Schema builder', () => {
2930
nullable: false
3031
});
3132
});
33+
it('builds integer schema with options and overrides', () => {
34+
const schema = Schema.integer({ nullable: true, format: 'int32' });
35+
expect(schema.toRequest()).to.eql({
36+
type: 'integer',
37+
format: 'int32',
38+
nullable: true
39+
});
40+
});
3241
it('builds number schema', () => {
3342
const schema = Schema.number();
3443
expect(schema.toRequest()).to.eql({
3544
type: 'number',
3645
nullable: false
3746
});
3847
});
48+
it('builds number schema with options and unknown options', () => {
49+
const schema = Schema.number({ format: 'float', futureOption: 'test' });
50+
expect(schema.toRequest()).to.eql({
51+
type: 'number',
52+
format: 'float',
53+
futureOption: 'test',
54+
nullable: false
55+
});
56+
});
3957
it('builds boolean schema', () => {
4058
const schema = Schema.boolean();
4159
expect(schema.toRequest()).to.eql({
@@ -81,6 +99,48 @@ describe.only('Schema builder', () => {
8199
required: ['someInput']
82100
});
83101
});
102+
it('builds an object schema', () => {
103+
const schema = Schema.object({
104+
properties: {
105+
'someInput': Schema.string()
106+
}
107+
});
108+
expect(schema.toRequest()).to.eql({
109+
type: 'object',
110+
nullable: false,
111+
properties: {
112+
'someInput': {
113+
type: 'string',
114+
nullable: false
115+
}
116+
},
117+
required: ['someInput']
118+
});
119+
});
120+
it('builds an object schema with optional properties', () => {
121+
const schema = Schema.object({
122+
properties: {
123+
'someInput': Schema.string(),
124+
'someBool': Schema.boolean()
125+
},
126+
optionalProperties: ['someBool']
127+
});
128+
expect(schema.toRequest()).to.eql({
129+
type: 'object',
130+
nullable: false,
131+
properties: {
132+
'someInput': {
133+
type: 'string',
134+
nullable: false
135+
},
136+
'someBool': {
137+
type: 'boolean',
138+
nullable: false
139+
}
140+
},
141+
required: ['someInput']
142+
});
143+
});
84144
it('builds layered schema - partially filled out', () => {
85145
const schema = Schema.array({
86146
items: Schema.object({
@@ -192,6 +252,17 @@ describe.only('Schema builder', () => {
192252
'required': ['country', 'population']
193253
});
194254
});
255+
it('throws if an optionalProperties item does not exist', () => {
256+
const schema = Schema.object({
257+
properties: {
258+
country: Schema.string(),
259+
elevation: Schema.number(),
260+
population: Schema.integer({ nullable: true })
261+
},
262+
optionalProperties: ['cat']
263+
});
264+
expect(() => schema.toRequest()).to.throw(VertexAIErrorCode.INVALID_SCHEMA);
265+
});
195266
});
196267

197268
const layeredSchemaOutputPartial = {

packages/vertexai/src/requests/schema-builder.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { VertexAIError } from '../errors';
2+
import { VertexAIErrorCode } from '../types';
13
import {
24
SchemaInterface,
35
SchemaType,
@@ -25,12 +27,19 @@ export abstract class Schema implements SchemaInterface {
2527
nullable: boolean;
2628
/** Optional. The example of the property. */
2729
example?: unknown;
30+
/**
31+
* Allows user to add other schema properties that have not yet
32+
* been officially added to the SDK.
33+
*/
34+
[key: string]: unknown;
2835

2936
constructor(schemaParams: SchemaInterface) {
37+
// eslint-disable-next-line guard-for-in
38+
for (const paramKey in schemaParams) {
39+
this[paramKey] = schemaParams[paramKey];
40+
}
41+
// Ensure these are explicitly set to avoid TS errors.
3042
this.type = schemaParams.type;
31-
this.format = schemaParams?.format;
32-
this.description = schemaParams?.description;
33-
this.example = schemaParams?.example;
3443
this.nullable = schemaParams.hasOwnProperty('nullable')
3544
? !!schemaParams.nullable
3645
: false;
@@ -127,6 +136,7 @@ export class IntegerSchema extends Schema {
127136
});
128137
}
129138
}
139+
130140
export class NumberSchema extends Schema {
131141
constructor(schemaParams?: SchemaParams) {
132142
super({
@@ -135,6 +145,7 @@ export class NumberSchema extends Schema {
135145
});
136146
}
137147
}
148+
138149
export class BooleanSchema extends Schema {
139150
constructor(schemaParams?: SchemaParams) {
140151
super({
@@ -194,19 +205,28 @@ export class ObjectSchema extends Schema {
194205

195206
toRequest(): _SchemaRequest {
196207
const obj = super.toRequest();
197-
const properties: Record<string, _SchemaRequest> = {};
208+
obj.properties = this.properties;
198209
const required = [];
210+
if (this.optionalProperties) {
211+
for (const propertyKey of this.optionalProperties) {
212+
if (!this.properties.hasOwnProperty(propertyKey)) {
213+
throw new VertexAIError(
214+
VertexAIErrorCode.INVALID_SCHEMA,
215+
`Property "${propertyKey}" specified in "optionalProperties" does not exist.`
216+
);
217+
}
218+
}
219+
}
199220
for (const propertyKey in this.properties) {
200221
if (this.properties.hasOwnProperty(propertyKey)) {
201-
properties[propertyKey] = this.properties[
222+
obj.properties[propertyKey] = this.properties[
202223
propertyKey
203224
].toRequest() as _SchemaRequest;
204225
if (!this.optionalProperties.includes(propertyKey)) {
205226
required.push(propertyKey);
206227
}
207228
}
208229
}
209-
obj.properties = properties;
210230
if (required.length > 0) {
211231
obj.required = required;
212232
}

packages/vertexai/src/types/error.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ export const enum VertexAIErrorCode {
7878
/** An error associated with a Content object. */
7979
INVALID_CONTENT = 'invalid-content',
8080

81+
/** An error due to invalid Schema input. */
82+
INVALID_SCHEMA = 'invalid-schema',
83+
8184
/** An error occurred due to a missing Firebase API key. */
8285
NO_API_KEY = 'no-api-key',
8386

packages/vertexai/src/types/schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ interface SchemaShared<T> {
3535
example?: unknown;
3636
/** Optional. Whether the property is nullable. */
3737
nullable?: boolean;
38+
[key: string]: unknown;
3839
}
3940

4041
/**

0 commit comments

Comments
 (0)