Skip to content

Commit 1e96569

Browse files
committed
feat: 🎸 improve discriminator expression builder
1 parent 8514f3e commit 1e96569

File tree

4 files changed

+72
-9
lines changed

4 files changed

+72
-9
lines changed

src/__tests__/fixtures.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
import {RandomJson} from '@jsonjoy.com/json-random';
88
import {genRandomExample} from '@jsonjoy.com/json-random/lib/examples';
99
import {s} from '../schema';
10-
import {t} from '../type';
10+
import {ModuleType} from '../type/classes/ModuleType';
11+
import type {Type} from '../type';
12+
13+
const mod = new ModuleType();
14+
export const t = mod.t;
1115

1216
export const randomJson = () => {
1317
return Math.random() < 0.5 ? genRandomExample() : RandomJson.generate();
@@ -78,6 +82,18 @@ export const schemaCategories = {
7882
all: allSchemas,
7983
} as const;
8084

85+
const primitivesModule = new ModuleType();
86+
export const primitiveTypes = Object.entries(primitiveSchemas).reduce((acc, [key, schema]) => {
87+
acc[key] = primitivesModule.t.import(schema);
88+
return acc;
89+
}, {} as Record<string, Type>);
90+
91+
const compositesModule = new ModuleType();
92+
export const compositeTypes = Object.entries(compositeSchemas).reduce((acc, [key, schema]) => {
93+
acc[key] = compositesModule.t.import(schema);
94+
return acc;
95+
}, {} as Record<string, Type>);
96+
8197
/**
8298
* User profile schema with nested objects and optional fields
8399
*/
@@ -92,7 +108,8 @@ export const User = t
92108
age: t.Number({gte: 0, lte: 150}),
93109
verified: t.bool,
94110
})
95-
.opt('avatar', t.String({format: 'ascii'}));
111+
.opt('avatar', t.String({format: 'ascii'}))
112+
.alias('User').type;
96113

97114
/**
98115
* Product catalog schema with arrays and formatted numbers
@@ -189,7 +206,7 @@ export const Event = t.Object(
189206
t.Key('location', t.Tuple([t.Number({format: 'f64'}), t.Number({format: 'f64'})])),
190207
t.Key('metadata', t.Map(t.Or(t.str, t.num, t.bool))),
191208
t.KeyOpt('sessionId', t.str),
192-
);
209+
).alias('Event').type;
193210

194211
/**
195212
* Contact information schema with formatted strings
@@ -287,3 +304,18 @@ export const ComplexNested = t.Object(
287304
}),
288305
),
289306
);
307+
308+
export const allSerializableTypes = {
309+
...primitiveTypes,
310+
...compositeTypes,
311+
User,
312+
Product,
313+
BlogPost,
314+
ApiResponse,
315+
FileMetadata,
316+
Configuration,
317+
Event,
318+
ContactInfo,
319+
DatabaseRecord,
320+
ComplexNested,
321+
} as const;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {Writer} from '@jsonjoy.com/buffers/lib/Writer';
2+
import {CborDecoder} from '@jsonjoy.com/json-pack/lib/cbor/CborDecoder';
3+
import {CborEncoder} from '@jsonjoy.com/json-pack/lib/cbor/CborEncoder';
4+
import {CborCodegen} from '../CborCodegen';
5+
import {Random} from '../../../../random';
6+
import {allSerializableTypes} from '../../../../__tests__/fixtures';
7+
8+
const encoder = new CborEncoder(new Writer(16));
9+
const decoder = new CborDecoder();
10+
11+
for (const [name, type] of Object.entries(allSerializableTypes)) {
12+
test(`can encode and decode ${name}`, () => {
13+
for (let i = 0; i < 100; i++) {
14+
const json = Random.gen(type);
15+
try {
16+
const fn = CborCodegen.get(type);
17+
fn(json, encoder);
18+
const encoded = encoder.writer.flush();
19+
const decoded = decoder.decode(encoded);
20+
expect(decoded).toEqual(json);
21+
} catch (error) {
22+
console.log(JSON.stringify(json, null, 2));
23+
console.log(type + '');
24+
throw error;
25+
}
26+
}
27+
});
28+
}

src/type/classes/ModuleType/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import {printTree} from 'tree-dump/lib/printTree';
2-
import type {Printable} from 'tree-dump/lib/types';
3-
import type {KeySchema, ModuleSchema, ObjSchema, Schema, TypeMap} from '../../../schema';
42
import {Walker} from '../../../schema/Walker';
5-
import type {Type} from '../../../type';
63
import {TypeBuilder} from '../../TypeBuilder';
74
import {AliasType} from '../AliasType';
5+
import type {Printable} from 'tree-dump/lib/types';
6+
import type {KeySchema, ModuleSchema, ObjSchema, Schema, TypeMap} from '../../../schema';
7+
import type {Type} from '../../../type';
88
import type {RefType} from '../RefType';
99

1010
export class ModuleType implements Printable {

src/type/discriminator.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import type {Expr} from '@jsonjoy.com/json-expression';
21
import {ArrType, BoolType, ConType, NumType, type KeyType, ObjType, StrType} from './classes';
2+
import type {Expr} from '@jsonjoy.com/json-expression';
33
import type {OrType, RefType, Type} from './types';
44

55
/**
@@ -79,7 +79,10 @@ export class Discriminator {
7979
const length = types.length;
8080
const expanded: Type[] = [];
8181
const expand = (type: Type): Type[] => {
82-
if (type.kind() === 'ref') type = (type as RefType).resolve();
82+
while (type.kind() === 'ref' || type.kind() === 'key') {
83+
if (type.kind() === 'ref') type = (type as RefType).resolve();
84+
if (type.kind() === 'key') type = (type as KeyType<any, Type>).val;
85+
}
8386
if (type.kind() === 'or') return (type as OrType).types.flatMap((t: Type) => expand(t));
8487
return [type];
8588
};
@@ -108,7 +111,7 @@ export class Discriminator {
108111
) {}
109112

110113
condition(): Expr {
111-
if (this.type instanceof ConType) return ['==', this.type.literal(), ['$', this.path]];
114+
if (this.type instanceof ConType) return ['==', this.type.literal(), ['$', this.path, this.type.literal() === null ? '' : null]];
112115
if (this.type instanceof BoolType) return ['==', ['type', ['$', this.path]], 'boolean'];
113116
if (this.type instanceof NumType) return ['==', ['type', ['$', this.path]], 'number'];
114117
if (this.type instanceof StrType) return ['==', ['type', ['$', this.path]], 'string'];

0 commit comments

Comments
 (0)