Skip to content

Commit

Permalink
All tests passing, primitive array tests added.
Browse files Browse the repository at this point in the history
  • Loading branch information
mbrich committed Jun 2, 2024
1 parent 32f1656 commit af6f37a
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 28 deletions.
48 changes: 26 additions & 22 deletions src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,22 +92,29 @@ export class Schema<DataT, InputT extends SchemaData<DataT>, VerifiedT = InputT>
public async verifyField(
field: SchemaField<InputT>,
value: unknown,
path: Tracer,
tracer: Tracer,
base: Log
): Promise<Fate<VerifiedField<DataT>>> {
const fate = new Fate<VerifiedField<DataT>>();
): Promise<Fate<VerifiedField<DataT> | VerifiedField<DataT>[]>> {
const fate = new Fate<VerifiedField<DataT> | VerifiedField<DataT>[]>();

if (!field) {
return fate.setErrorCode(schemaError(`missing_field`, path.current()));
return fate.setErrorCode(schemaError(`missing_field`, tracer.current()));
}

const currPath = path.child(field.name);
const currPath = tracer.child(field.name);

if (value === undefined) {
return fate.setErrorCode(schemaError('missing_field_value', currPath.current()));
}

const verified = await this.verifyFieldValues(field, value, path, base);
let verified: Fate<VerifiedField<DataT> | VerifiedField<DataT>[]>;

if (Array.isArray(value)) {
verified = await this.verifyFieldValues(field, value, currPath, base);
} else {
// If the field is not an array, let the single field value verifier handle it.
verified = await this.verifyFieldValue(field, value, tracer.child(field.name), base);
}

if (!verified.ok()) {
return fate.setErrorCode(verified.errorCode());
Expand Down Expand Up @@ -136,19 +143,14 @@ export class Schema<DataT, InputT extends SchemaData<DataT>, VerifiedT = InputT>

public async verifyFieldValues(
field: SchemaField<InputT>,
values: unknown | unknown[],
values: unknown[],
tracer: Tracer,
base: Log
): Promise<Fate<VerifiedField<DataT>>> {
const fate = new Fate<VerifiedField<DataT>>({
data: null
): Promise<Fate<VerifiedField<DataT>[]>> {
const fate = new Fate<VerifiedField<DataT>[]>({
data: []
});

// If the field is not an array, let the single field value verifier handle it.
if (!Array.isArray(values)) {
return this.verifyFieldValue(field, values, tracer.child(field.name), base);
}

const data: VerifiedField<DataT>[] = [];
let i = 0;
for (const value of values) {
Expand All @@ -160,13 +162,12 @@ export class Schema<DataT, InputT extends SchemaData<DataT>, VerifiedT = InputT>
);
i++;

if (!result.data) {
continue;
if (result.ok()) {
data.push(result.data);
}

data.push(result.data);
}

fate.data = data;
return fate.setSuccess(true);
}

Expand Down Expand Up @@ -344,6 +345,7 @@ export class Schema<DataT, InputT extends SchemaData<DataT>, VerifiedT = InputT>
);
}

// Verify input and return result without transform.
const verified = await this.verifyOnly(init);
if (!verified.ok()) {
return fate.setErrorCode(verified.errorCode());
Expand Down Expand Up @@ -381,8 +383,10 @@ export class Schema<DataT, InputT extends SchemaData<DataT>, VerifiedT = InputT>
* Verify provided data object's structure, content, and types against this schema.
* @param init
*/
public async verifyOnly(init: SchemaVerifyInit): Promise<Fate<VerifiedSchema<DataT>>> {
const fate = new Fate<VerifiedSchema<DataT>>();
public async verifyOnly(
init: SchemaVerifyInit
): Promise<Fate<VerifiedSchema<VerifiedField<DataT> | VerifiedField<DataT>[]>>> {
const fate = new Fate<VerifiedSchema<VerifiedField<DataT> | VerifiedField<DataT>[]>>();

const currPath = init.tracer ? init.tracer : new Tracer();
// Root schemas (no parent) use their schema name as the first path item. Child schemas DO NOT
Expand All @@ -407,7 +411,7 @@ export class Schema<DataT, InputT extends SchemaData<DataT>, VerifiedT = InputT>
const total = this.fields.size;
let processed = 0;
const fieldCount = this.fields.size;
const mapped = new Map<string, VerifiedField<DataT>>();
const mapped = new Map<string, VerifiedField<DataT> | VerifiedField<DataT>[]>();

if (fieldCount === 0) {
if (init?.flags?.allowEmptyInputObject !== true) {
Expand Down
3 changes: 2 additions & 1 deletion src/schema/output/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@
import {Fate} from '@toreda/fate';
import {Log} from '@toreda/log';
import {type VerifiedSchema} from '../../verified/schema';
import {type VerifiedField} from '../../verified/field';

/**
* Transform schema parser output.
*
* @category Schema – Transform Output
*/
export type SchemaOutputTransformer<DataT, VerifiedT> = (
mapped: VerifiedSchema<DataT>,
mapped: VerifiedSchema<VerifiedField<DataT> | VerifiedField<DataT>[]>,
base: Log
) => Promise<Fate<VerifiedT | null>>;
2 changes: 1 addition & 1 deletion src/verified/field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ import {type VerifiedSchema} from './schema';
*
* @category Schema – Field
*/
export type VerifiedField<DataT> = DataT | DataT[] | VerifiedSchema<DataT> | null;
export type VerifiedField<DataT = unknown> = DataT | VerifiedSchema<DataT> | null;
5 changes: 1 addition & 4 deletions src/verified/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,4 @@
*
* @category Schema
*/
export type VerifiedSchema<DataT> = Map<
string,
DataT | DataT[] | VerifiedSchema<DataT> | VerifiedSchema<DataT>[] | null
>;
export type VerifiedSchema<VerifiedT = unknown> = Map<string, VerifiedT>;
5 changes: 5 additions & 0 deletions tests/_data/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface SampleBData extends SchemaData<Primitive> {
export interface SampleAData extends SchemaData<Primitive> {
str1a: string;
int1a: number;
intArray: number[];
subValue: SampleBData;
}

Expand Down Expand Up @@ -55,6 +56,10 @@ export class SampleSchemaSubA extends Schema<Primitive, SampleAData, SampleAData
name: 'int1a',
types: ['number']
},
{
name: 'intArray',
types: ['number[]']
},
{
name: 'subValue',
types: ['ct2']
Expand Down
16 changes: 16 additions & 0 deletions tests/schema/recursive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ describe('Schema - Recursive Parsing', () => {
aData = {
int1a: 31,
str1a: 'aaa',
intArray: [1, 2, 3, 4, 5],
subValue: {
str2b: 'zzzzz',
int2b: 9999
Expand Down Expand Up @@ -118,5 +119,20 @@ describe('Schema - Recursive Parsing', () => {
);
expect(result.ok()).toBe(false);
});

it(`should verify a non-recursive array of primitives`, async () => {
const customB = new SampleSchemaSubB(base);
const customA = new SampleSchemaSubA(customB, base);

const result = await customA.verify({
data: aData,
base: base
});

expect(result.errorCode()).toBe(EMPTY_STRING);
expect(result.ok()).toBe(true);

expect(result.data?.intArray).toEqual(aData.intArray);
});
});
});

0 comments on commit af6f37a

Please sign in to comment.