Skip to content

Commit c6368e4

Browse files
Merge pull request #36 from elek-io/optional-to-nullable
Keys should be set by default and null when purposefully not set
2 parents ed50441 + 22770fd commit c6368e4

File tree

5 files changed

+58
-38
lines changed

5 files changed

+58
-38
lines changed

.changeset/afraid-hotels-compare.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@elek-io/shared': minor
3+
---
4+
5+
Instead of not setting keys at all, the user / Core / Client should set them as null to specify a value that is purposefully not set

src/fileSchema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const baseFileSchema = z.object({
2222
/**
2323
* The timestamp of the file being updated is set by the service of "objectType" while updating it
2424
*/
25-
updated: z.number().optional(),
25+
updated: z.number().nullable(),
2626
});
2727
export type BaseFile = z.infer<typeof baseFileSchema>;
2828

src/gitSchema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const gitCommitSchema = z.object({
2222
message: z.string(),
2323
author: gitSignatureSchema,
2424
timestamp: z.number(),
25-
tag: z.string().optional(),
25+
tag: z.string().nullable(),
2626
});
2727
export type GitCommit = z.infer<typeof gitCommitSchema>;
2828

src/valueSchema.ts

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -64,24 +64,24 @@ export type ValueDefinitionBase = z.infer<typeof ValueDefinitionBaseSchema>;
6464
export const StringValueDefinitionBaseSchema = ValueDefinitionBaseSchema.extend(
6565
{
6666
valueType: z.literal(ValueTypeSchema.Enum.string),
67-
defaultValue: z.string().optional(),
67+
defaultValue: z.string().nullable(),
6868
}
6969
);
7070

7171
export const textValueDefinitionSchema = StringValueDefinitionBaseSchema.extend(
7272
{
7373
inputType: z.literal(ValueInputTypeSchema.Enum.text),
74-
min: z.number().optional(),
75-
max: z.number().optional(),
74+
min: z.number().nullable(),
75+
max: z.number().nullable(),
7676
}
7777
);
7878
export type TextValueDefinition = z.infer<typeof textValueDefinitionSchema>;
7979

8080
export const textareaValueDefinitionSchema =
8181
StringValueDefinitionBaseSchema.extend({
8282
inputType: z.literal(ValueInputTypeSchema.Enum.textarea),
83-
min: z.number().optional(),
84-
max: z.number().optional(),
83+
min: z.number().nullable(),
84+
max: z.number().nullable(),
8585
});
8686
export type TextareaValueDefinition = z.infer<
8787
typeof textareaValueDefinitionSchema
@@ -90,7 +90,7 @@ export type TextareaValueDefinition = z.infer<
9090
export const emailValueDefinitionSchema =
9191
StringValueDefinitionBaseSchema.extend({
9292
inputType: z.literal(ValueInputTypeSchema.Enum.email),
93-
defaultValue: z.string().email().optional(),
93+
defaultValue: z.string().email().nullable(),
9494
});
9595
export type EmailValueDefinition = z.infer<typeof emailValueDefinitionSchema>;
9696

@@ -102,36 +102,36 @@ export type EmailValueDefinition = z.infer<typeof emailValueDefinitionSchema>;
102102

103103
export const urlValueDefinitionSchema = StringValueDefinitionBaseSchema.extend({
104104
inputType: z.literal(ValueInputTypeSchema.Enum.url),
105-
defaultValue: z.string().url().optional(),
105+
defaultValue: z.string().url().nullable(),
106106
});
107107
export type UrlValueDefinition = z.infer<typeof urlValueDefinitionSchema>;
108108

109109
export const ipValueDefinitionSchema = StringValueDefinitionBaseSchema.extend({
110110
inputType: z.literal(ValueInputTypeSchema.Enum.ip),
111-
defaultValue: z.string().ip().optional(),
111+
defaultValue: z.string().ip().nullable(),
112112
});
113113
export type IpValueDefinition = z.infer<typeof ipValueDefinitionSchema>;
114114

115115
export const dateValueDefinitionSchema = StringValueDefinitionBaseSchema.extend(
116116
{
117117
inputType: z.literal(ValueInputTypeSchema.Enum.date),
118-
defaultValue: z.string().date().optional(),
118+
defaultValue: z.string().date().nullable(),
119119
}
120120
);
121121
export type DateValueDefinition = z.infer<typeof dateValueDefinitionSchema>;
122122

123123
export const timeValueDefinitionSchema = StringValueDefinitionBaseSchema.extend(
124124
{
125125
inputType: z.literal(ValueInputTypeSchema.Enum.time),
126-
defaultValue: z.string().time().optional(),
126+
defaultValue: z.string().time().nullable(),
127127
}
128128
);
129129
export type TimeValueDefinition = z.infer<typeof timeValueDefinitionSchema>;
130130

131131
export const datetimeValueDefinitionSchema =
132132
StringValueDefinitionBaseSchema.extend({
133133
inputType: z.literal(ValueInputTypeSchema.Enum.datetime),
134-
defaultValue: z.string().datetime().optional(),
134+
defaultValue: z.string().datetime().nullable(),
135135
});
136136
export type DatetimeValueDefinition = z.infer<
137137
typeof datetimeValueDefinitionSchema
@@ -166,10 +166,10 @@ export type StringValueDefinition = z.infer<typeof stringValueDefinitionSchema>;
166166
export const NumberValueDefinitionBaseSchema = ValueDefinitionBaseSchema.extend(
167167
{
168168
valueType: z.literal(ValueTypeSchema.Enum.number),
169-
min: z.number().optional(),
170-
max: z.number().optional(),
169+
min: z.number().nullable(),
170+
max: z.number().nullable(),
171171
isUnique: z.literal(false),
172-
defaultValue: z.number().optional(),
172+
defaultValue: z.number().nullable(),
173173
}
174174
);
175175

@@ -182,7 +182,7 @@ export type NumberValueDefinition = z.infer<typeof numberValueDefinitionSchema>;
182182
export const rangeValueDefinitionSchema =
183183
NumberValueDefinitionBaseSchema.extend({
184184
inputType: z.literal(ValueInputTypeSchema.Enum.range),
185-
// Overwrite from optional to required because a range needs min, max and default to work and is required, since it always returns a number
185+
// Overwrite from nullable to required because a range needs min, max and default to work and is required, since it always returns a number
186186
isRequired: z.literal(true),
187187
min: z.number(),
188188
max: z.number(),
@@ -197,7 +197,7 @@ export type RangeValueDefinition = z.infer<typeof rangeValueDefinitionSchema>;
197197
export const BooleanValueDefinitionBaseSchema =
198198
ValueDefinitionBaseSchema.extend({
199199
valueType: z.literal(ValueTypeSchema.Enum.boolean),
200-
// Overwrite from optional to required because a boolean needs a default to work and is required, since it always is either true or false
200+
// Overwrite from nullable to required because a boolean needs a default to work and is required, since it always is either true or false
201201
isRequired: z.literal(true),
202202
defaultValue: z.boolean(),
203203
isUnique: z.literal(false),
@@ -221,18 +221,18 @@ export const ReferenceValueDefinitionBaseSchema =
221221
export const assetValueDefinitionSchema =
222222
ReferenceValueDefinitionBaseSchema.extend({
223223
inputType: z.literal(ValueInputTypeSchema.Enum.asset),
224-
allowedMimeTypes: z.array(supportedAssetMimeTypeSchema).optional(),
225-
min: z.number().optional(),
226-
max: z.number().optional(),
224+
allowedMimeTypes: z.array(supportedAssetMimeTypeSchema).min(1),
225+
min: z.number().nullable(),
226+
max: z.number().nullable(),
227227
});
228228
export type AssetValueDefinition = z.infer<typeof assetValueDefinitionSchema>;
229229

230230
export const entryValueDefinitionSchema =
231231
ReferenceValueDefinitionBaseSchema.extend({
232232
inputType: z.literal(ValueInputTypeSchema.Enum.entry),
233233
ofCollections: z.array(uuidSchema),
234-
min: z.number().optional(),
235-
max: z.number().optional(),
234+
min: z.number().nullable(),
235+
max: z.number().nullable(),
236236
});
237237
export type EntryValueDefinition = z.infer<typeof entryValueDefinitionSchema>;
238238

@@ -445,15 +445,15 @@ function getNumberValueContentSchema(
445445
) {
446446
let schema = z.number();
447447

448-
if ('min' in definition && definition.min) {
448+
if (definition.min) {
449449
schema = schema.min(definition.min);
450450
}
451-
if ('max' in definition && definition.max) {
451+
if (definition.max) {
452452
schema = schema.max(definition.max);
453453
}
454454

455455
if (definition.isRequired === false) {
456-
return schema.optional();
456+
return schema.nullable();
457457
}
458458

459459
return schema;
@@ -494,15 +494,12 @@ function getStringValueContentSchema(definition: StringValueDefinition) {
494494
}
495495

496496
if (definition.isRequired === false) {
497-
return schema.optional();
497+
return schema.nullable();
498498
}
499499

500500
return schema.min(1, 'shared.stringValueRequired'); // @see https://github.com/colinhacks/zod/issues/2466
501501
}
502502

503-
/**
504-
* @todo what do we need inside the asset reference (inside the values content), to resolve and validate their schema?
505-
*/
506503
function getReferenceValueContentSchema(
507504
definition: AssetValueDefinition | EntryValueDefinition // | SharedValueValueDefinition
508505
) {

test/valueSchema.test.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,12 @@ describe('Dynamic zod schema', () => {
8989
optionalNumberValueschema.parse(5);
9090
optionalNumberValueschema.parse(10);
9191
optionalNumberValueschema.parse(7.5);
92-
optionalNumberValueschema.parse(undefined);
92+
optionalNumberValueschema.parse(null);
9393

9494
expect(() => optionalNumberValueschema.parse(4)).toThrow();
9595
expect(() => optionalNumberValueschema.parse(11)).toThrow();
9696
expect(() => optionalNumberValueschema.parse('')).toThrow();
97-
expect(() => optionalNumberValueschema.parse(null)).toThrow();
97+
expect(() => optionalNumberValueschema.parse(undefined)).toThrow();
9898
expect(() => optionalNumberValueschema.parse(0)).toThrow();
9999
expect(() => optionalNumberValueschema.parse([])).toThrow();
100100
expect(() => optionalNumberValueschema.parse({})).toThrow();
@@ -190,13 +190,13 @@ describe('Dynamic zod schema', () => {
190190
});
191191

192192
optionalTextValueschema.parse('123456');
193-
optionalTextValueschema.parse(undefined);
193+
optionalTextValueschema.parse(null);
194194

195195
expect(() => optionalTextValueschema.parse(6)).toThrow();
196196
expect(() => optionalTextValueschema.parse(123456)).toThrow();
197197
expect(() => optionalTextValueschema.parse('')).toThrow();
198198
expect(() => optionalTextValueschema.parse(' ')).toThrow();
199-
expect(() => optionalTextValueschema.parse(null)).toThrow();
199+
expect(() => optionalTextValueschema.parse(undefined)).toThrow();
200200
expect(() => optionalTextValueschema.parse(0)).toThrow();
201201
expect(() => optionalTextValueschema.parse([])).toThrow();
202202
expect(() => optionalTextValueschema.parse({})).toThrow();
@@ -213,6 +213,7 @@ describe('Dynamic zod schema', () => {
213213
description: {
214214
en: 'Test',
215215
},
216+
defaultValue: null,
216217
inputWidth: '12',
217218
isDisabled: false,
218219
isRequired: true,
@@ -246,19 +247,20 @@ describe('Dynamic zod schema', () => {
246247
en: 'Test',
247248
},
248249
inputWidth: '12',
250+
defaultValue: null,
249251
isDisabled: false,
250252
isRequired: false,
251253
isUnique: false,
252254
});
253255

254256
optionalEmailValueschema.parse(faker.internet.email());
255-
optionalEmailValueschema.parse(undefined);
257+
optionalEmailValueschema.parse(null);
256258

257259
expect(() => optionalEmailValueschema.parse(6)).toThrow();
258260
expect(() => optionalEmailValueschema.parse(123456)).toThrow();
259261
expect(() => optionalEmailValueschema.parse('')).toThrow();
260262
expect(() => optionalEmailValueschema.parse(' ')).toThrow();
261-
expect(() => optionalEmailValueschema.parse(null)).toThrow();
263+
expect(() => optionalEmailValueschema.parse(undefined)).toThrow();
262264
expect(() => optionalEmailValueschema.parse(0)).toThrow();
263265
expect(() => optionalEmailValueschema.parse([])).toThrow();
264266
expect(() => optionalEmailValueschema.parse({})).toThrow();
@@ -276,6 +278,7 @@ describe('Dynamic zod schema', () => {
276278
en: 'Test',
277279
},
278280
inputWidth: '12',
281+
defaultValue: null,
279282
isDisabled: false,
280283
isRequired: true,
281284
isUnique: false,
@@ -324,17 +327,18 @@ describe('Dynamic zod schema', () => {
324327
en: 'Test',
325328
},
326329
inputWidth: '12',
330+
defaultValue: null,
327331
isDisabled: false,
328332
isRequired: false,
329333
isUnique: false,
330334
});
331335

332336
optionalUrlValueschema.parse('http://example.com');
333337
optionalUrlValueschema.parse('https://example.com');
334-
optionalUrlValueschema.parse(undefined);
338+
optionalUrlValueschema.parse(null);
335339

336340
expect(() => optionalUrlValueschema.parse('')).toThrow();
337-
expect(() => optionalUrlValueschema.parse(null)).toThrow();
341+
expect(() => optionalUrlValueschema.parse(undefined)).toThrow();
338342
expect(() => optionalUrlValueschema.parse(0)).toThrow();
339343
expect(() => optionalUrlValueschema.parse([])).toThrow();
340344
expect(() => optionalUrlValueschema.parse({})).toThrow();
@@ -352,6 +356,7 @@ describe('Dynamic zod schema', () => {
352356
en: 'Test',
353357
},
354358
inputWidth: '12',
359+
defaultValue: null,
355360
isDisabled: false,
356361
isRequired: true,
357362
isUnique: false,
@@ -380,6 +385,7 @@ describe('Dynamic zod schema', () => {
380385
en: 'Test',
381386
},
382387
inputWidth: '12',
388+
defaultValue: null,
383389
isDisabled: false,
384390
isRequired: true,
385391
isUnique: false,
@@ -408,6 +414,7 @@ describe('Dynamic zod schema', () => {
408414
en: 'Test',
409415
},
410416
inputWidth: '12',
417+
defaultValue: null,
411418
isDisabled: false,
412419
isRequired: true,
413420
isUnique: false,
@@ -436,6 +443,7 @@ describe('Dynamic zod schema', () => {
436443
en: 'Test',
437444
},
438445
inputWidth: '12',
446+
defaultValue: null,
439447
isDisabled: false,
440448
isRequired: true,
441449
isUnique: false,
@@ -464,6 +472,7 @@ describe('Dynamic zod schema', () => {
464472
en: 'Test',
465473
},
466474
inputWidth: '12',
475+
defaultValue: null,
467476
isDisabled: false,
468477
isRequired: true,
469478
isUnique: false,
@@ -491,6 +500,9 @@ describe('Dynamic zod schema', () => {
491500
en: 'Test',
492501
},
493502
inputWidth: '12',
503+
min: null,
504+
max: null,
505+
allowedMimeTypes: ['image/png'],
494506
isDisabled: false,
495507
isRequired: true,
496508
isUnique: false,
@@ -532,6 +544,9 @@ describe('Dynamic zod schema', () => {
532544
en: 'Test',
533545
},
534546
inputWidth: '12',
547+
min: null,
548+
max: null,
549+
allowedMimeTypes: ['image/png'],
535550
isDisabled: false,
536551
isRequired: false,
537552
isUnique: false,
@@ -567,6 +582,7 @@ describe('Dynamic zod schema', () => {
567582
},
568583
min: 2,
569584
max: 3,
585+
allowedMimeTypes: ['image/png'],
570586
inputWidth: '12',
571587
isDisabled: false,
572588
isRequired: true,
@@ -657,6 +673,8 @@ describe('Dynamic zod schema', () => {
657673
en: 'Test',
658674
},
659675
inputWidth: '12',
676+
min: null,
677+
max: null,
660678
ofCollections: [uuid()],
661679
isDisabled: false,
662680
isRequired: true,

0 commit comments

Comments
 (0)