Skip to content

Commit

Permalink
Merge pull request #36 from elek-io/optional-to-nullable
Browse files Browse the repository at this point in the history
Keys should be set by default and null when purposefully not set
  • Loading branch information
Nils-Kolvenbach authored Jun 25, 2024
2 parents ed50441 + 22770fd commit c6368e4
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .changeset/afraid-hotels-compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@elek-io/shared': minor
---

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
2 changes: 1 addition & 1 deletion src/fileSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const baseFileSchema = z.object({
/**
* The timestamp of the file being updated is set by the service of "objectType" while updating it
*/
updated: z.number().optional(),
updated: z.number().nullable(),
});
export type BaseFile = z.infer<typeof baseFileSchema>;

Expand Down
2 changes: 1 addition & 1 deletion src/gitSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const gitCommitSchema = z.object({
message: z.string(),
author: gitSignatureSchema,
timestamp: z.number(),
tag: z.string().optional(),
tag: z.string().nullable(),
});
export type GitCommit = z.infer<typeof gitCommitSchema>;

Expand Down
53 changes: 25 additions & 28 deletions src/valueSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,24 +64,24 @@ export type ValueDefinitionBase = z.infer<typeof ValueDefinitionBaseSchema>;
export const StringValueDefinitionBaseSchema = ValueDefinitionBaseSchema.extend(
{
valueType: z.literal(ValueTypeSchema.Enum.string),
defaultValue: z.string().optional(),
defaultValue: z.string().nullable(),
}
);

export const textValueDefinitionSchema = StringValueDefinitionBaseSchema.extend(
{
inputType: z.literal(ValueInputTypeSchema.Enum.text),
min: z.number().optional(),
max: z.number().optional(),
min: z.number().nullable(),
max: z.number().nullable(),
}
);
export type TextValueDefinition = z.infer<typeof textValueDefinitionSchema>;

export const textareaValueDefinitionSchema =
StringValueDefinitionBaseSchema.extend({
inputType: z.literal(ValueInputTypeSchema.Enum.textarea),
min: z.number().optional(),
max: z.number().optional(),
min: z.number().nullable(),
max: z.number().nullable(),
});
export type TextareaValueDefinition = z.infer<
typeof textareaValueDefinitionSchema
Expand All @@ -90,7 +90,7 @@ export type TextareaValueDefinition = z.infer<
export const emailValueDefinitionSchema =
StringValueDefinitionBaseSchema.extend({
inputType: z.literal(ValueInputTypeSchema.Enum.email),
defaultValue: z.string().email().optional(),
defaultValue: z.string().email().nullable(),
});
export type EmailValueDefinition = z.infer<typeof emailValueDefinitionSchema>;

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

export const urlValueDefinitionSchema = StringValueDefinitionBaseSchema.extend({
inputType: z.literal(ValueInputTypeSchema.Enum.url),
defaultValue: z.string().url().optional(),
defaultValue: z.string().url().nullable(),
});
export type UrlValueDefinition = z.infer<typeof urlValueDefinitionSchema>;

export const ipValueDefinitionSchema = StringValueDefinitionBaseSchema.extend({
inputType: z.literal(ValueInputTypeSchema.Enum.ip),
defaultValue: z.string().ip().optional(),
defaultValue: z.string().ip().nullable(),
});
export type IpValueDefinition = z.infer<typeof ipValueDefinitionSchema>;

export const dateValueDefinitionSchema = StringValueDefinitionBaseSchema.extend(
{
inputType: z.literal(ValueInputTypeSchema.Enum.date),
defaultValue: z.string().date().optional(),
defaultValue: z.string().date().nullable(),
}
);
export type DateValueDefinition = z.infer<typeof dateValueDefinitionSchema>;

export const timeValueDefinitionSchema = StringValueDefinitionBaseSchema.extend(
{
inputType: z.literal(ValueInputTypeSchema.Enum.time),
defaultValue: z.string().time().optional(),
defaultValue: z.string().time().nullable(),
}
);
export type TimeValueDefinition = z.infer<typeof timeValueDefinitionSchema>;

export const datetimeValueDefinitionSchema =
StringValueDefinitionBaseSchema.extend({
inputType: z.literal(ValueInputTypeSchema.Enum.datetime),
defaultValue: z.string().datetime().optional(),
defaultValue: z.string().datetime().nullable(),
});
export type DatetimeValueDefinition = z.infer<
typeof datetimeValueDefinitionSchema
Expand Down Expand Up @@ -166,10 +166,10 @@ export type StringValueDefinition = z.infer<typeof stringValueDefinitionSchema>;
export const NumberValueDefinitionBaseSchema = ValueDefinitionBaseSchema.extend(
{
valueType: z.literal(ValueTypeSchema.Enum.number),
min: z.number().optional(),
max: z.number().optional(),
min: z.number().nullable(),
max: z.number().nullable(),
isUnique: z.literal(false),
defaultValue: z.number().optional(),
defaultValue: z.number().nullable(),
}
);

Expand All @@ -182,7 +182,7 @@ export type NumberValueDefinition = z.infer<typeof numberValueDefinitionSchema>;
export const rangeValueDefinitionSchema =
NumberValueDefinitionBaseSchema.extend({
inputType: z.literal(ValueInputTypeSchema.Enum.range),
// Overwrite from optional to required because a range needs min, max and default to work and is required, since it always returns a number
// Overwrite from nullable to required because a range needs min, max and default to work and is required, since it always returns a number
isRequired: z.literal(true),
min: z.number(),
max: z.number(),
Expand All @@ -197,7 +197,7 @@ export type RangeValueDefinition = z.infer<typeof rangeValueDefinitionSchema>;
export const BooleanValueDefinitionBaseSchema =
ValueDefinitionBaseSchema.extend({
valueType: z.literal(ValueTypeSchema.Enum.boolean),
// Overwrite from optional to required because a boolean needs a default to work and is required, since it always is either true or false
// Overwrite from nullable to required because a boolean needs a default to work and is required, since it always is either true or false
isRequired: z.literal(true),
defaultValue: z.boolean(),
isUnique: z.literal(false),
Expand All @@ -221,18 +221,18 @@ export const ReferenceValueDefinitionBaseSchema =
export const assetValueDefinitionSchema =
ReferenceValueDefinitionBaseSchema.extend({
inputType: z.literal(ValueInputTypeSchema.Enum.asset),
allowedMimeTypes: z.array(supportedAssetMimeTypeSchema).optional(),
min: z.number().optional(),
max: z.number().optional(),
allowedMimeTypes: z.array(supportedAssetMimeTypeSchema).min(1),
min: z.number().nullable(),
max: z.number().nullable(),
});
export type AssetValueDefinition = z.infer<typeof assetValueDefinitionSchema>;

export const entryValueDefinitionSchema =
ReferenceValueDefinitionBaseSchema.extend({
inputType: z.literal(ValueInputTypeSchema.Enum.entry),
ofCollections: z.array(uuidSchema),
min: z.number().optional(),
max: z.number().optional(),
min: z.number().nullable(),
max: z.number().nullable(),
});
export type EntryValueDefinition = z.infer<typeof entryValueDefinitionSchema>;

Expand Down Expand Up @@ -445,15 +445,15 @@ function getNumberValueContentSchema(
) {
let schema = z.number();

if ('min' in definition && definition.min) {
if (definition.min) {
schema = schema.min(definition.min);
}
if ('max' in definition && definition.max) {
if (definition.max) {
schema = schema.max(definition.max);
}

if (definition.isRequired === false) {
return schema.optional();
return schema.nullable();
}

return schema;
Expand Down Expand Up @@ -494,15 +494,12 @@ function getStringValueContentSchema(definition: StringValueDefinition) {
}

if (definition.isRequired === false) {
return schema.optional();
return schema.nullable();
}

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

/**
* @todo what do we need inside the asset reference (inside the values content), to resolve and validate their schema?
*/
function getReferenceValueContentSchema(
definition: AssetValueDefinition | EntryValueDefinition // | SharedValueValueDefinition
) {
Expand Down
34 changes: 26 additions & 8 deletions test/valueSchema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ describe('Dynamic zod schema', () => {
optionalNumberValueschema.parse(5);
optionalNumberValueschema.parse(10);
optionalNumberValueschema.parse(7.5);
optionalNumberValueschema.parse(undefined);
optionalNumberValueschema.parse(null);

expect(() => optionalNumberValueschema.parse(4)).toThrow();
expect(() => optionalNumberValueschema.parse(11)).toThrow();
expect(() => optionalNumberValueschema.parse('')).toThrow();
expect(() => optionalNumberValueschema.parse(null)).toThrow();
expect(() => optionalNumberValueschema.parse(undefined)).toThrow();
expect(() => optionalNumberValueschema.parse(0)).toThrow();
expect(() => optionalNumberValueschema.parse([])).toThrow();
expect(() => optionalNumberValueschema.parse({})).toThrow();
Expand Down Expand Up @@ -190,13 +190,13 @@ describe('Dynamic zod schema', () => {
});

optionalTextValueschema.parse('123456');
optionalTextValueschema.parse(undefined);
optionalTextValueschema.parse(null);

expect(() => optionalTextValueschema.parse(6)).toThrow();
expect(() => optionalTextValueschema.parse(123456)).toThrow();
expect(() => optionalTextValueschema.parse('')).toThrow();
expect(() => optionalTextValueschema.parse(' ')).toThrow();
expect(() => optionalTextValueschema.parse(null)).toThrow();
expect(() => optionalTextValueschema.parse(undefined)).toThrow();
expect(() => optionalTextValueschema.parse(0)).toThrow();
expect(() => optionalTextValueschema.parse([])).toThrow();
expect(() => optionalTextValueschema.parse({})).toThrow();
Expand All @@ -213,6 +213,7 @@ describe('Dynamic zod schema', () => {
description: {
en: 'Test',
},
defaultValue: null,
inputWidth: '12',
isDisabled: false,
isRequired: true,
Expand Down Expand Up @@ -246,19 +247,20 @@ describe('Dynamic zod schema', () => {
en: 'Test',
},
inputWidth: '12',
defaultValue: null,
isDisabled: false,
isRequired: false,
isUnique: false,
});

optionalEmailValueschema.parse(faker.internet.email());
optionalEmailValueschema.parse(undefined);
optionalEmailValueschema.parse(null);

expect(() => optionalEmailValueschema.parse(6)).toThrow();
expect(() => optionalEmailValueschema.parse(123456)).toThrow();
expect(() => optionalEmailValueschema.parse('')).toThrow();
expect(() => optionalEmailValueschema.parse(' ')).toThrow();
expect(() => optionalEmailValueschema.parse(null)).toThrow();
expect(() => optionalEmailValueschema.parse(undefined)).toThrow();
expect(() => optionalEmailValueschema.parse(0)).toThrow();
expect(() => optionalEmailValueschema.parse([])).toThrow();
expect(() => optionalEmailValueschema.parse({})).toThrow();
Expand All @@ -276,6 +278,7 @@ describe('Dynamic zod schema', () => {
en: 'Test',
},
inputWidth: '12',
defaultValue: null,
isDisabled: false,
isRequired: true,
isUnique: false,
Expand Down Expand Up @@ -324,17 +327,18 @@ describe('Dynamic zod schema', () => {
en: 'Test',
},
inputWidth: '12',
defaultValue: null,
isDisabled: false,
isRequired: false,
isUnique: false,
});

optionalUrlValueschema.parse('http://example.com');
optionalUrlValueschema.parse('https://example.com');
optionalUrlValueschema.parse(undefined);
optionalUrlValueschema.parse(null);

expect(() => optionalUrlValueschema.parse('')).toThrow();
expect(() => optionalUrlValueschema.parse(null)).toThrow();
expect(() => optionalUrlValueschema.parse(undefined)).toThrow();
expect(() => optionalUrlValueschema.parse(0)).toThrow();
expect(() => optionalUrlValueschema.parse([])).toThrow();
expect(() => optionalUrlValueschema.parse({})).toThrow();
Expand All @@ -352,6 +356,7 @@ describe('Dynamic zod schema', () => {
en: 'Test',
},
inputWidth: '12',
defaultValue: null,
isDisabled: false,
isRequired: true,
isUnique: false,
Expand Down Expand Up @@ -380,6 +385,7 @@ describe('Dynamic zod schema', () => {
en: 'Test',
},
inputWidth: '12',
defaultValue: null,
isDisabled: false,
isRequired: true,
isUnique: false,
Expand Down Expand Up @@ -408,6 +414,7 @@ describe('Dynamic zod schema', () => {
en: 'Test',
},
inputWidth: '12',
defaultValue: null,
isDisabled: false,
isRequired: true,
isUnique: false,
Expand Down Expand Up @@ -436,6 +443,7 @@ describe('Dynamic zod schema', () => {
en: 'Test',
},
inputWidth: '12',
defaultValue: null,
isDisabled: false,
isRequired: true,
isUnique: false,
Expand Down Expand Up @@ -464,6 +472,7 @@ describe('Dynamic zod schema', () => {
en: 'Test',
},
inputWidth: '12',
defaultValue: null,
isDisabled: false,
isRequired: true,
isUnique: false,
Expand Down Expand Up @@ -491,6 +500,9 @@ describe('Dynamic zod schema', () => {
en: 'Test',
},
inputWidth: '12',
min: null,
max: null,
allowedMimeTypes: ['image/png'],
isDisabled: false,
isRequired: true,
isUnique: false,
Expand Down Expand Up @@ -532,6 +544,9 @@ describe('Dynamic zod schema', () => {
en: 'Test',
},
inputWidth: '12',
min: null,
max: null,
allowedMimeTypes: ['image/png'],
isDisabled: false,
isRequired: false,
isUnique: false,
Expand Down Expand Up @@ -567,6 +582,7 @@ describe('Dynamic zod schema', () => {
},
min: 2,
max: 3,
allowedMimeTypes: ['image/png'],
inputWidth: '12',
isDisabled: false,
isRequired: true,
Expand Down Expand Up @@ -657,6 +673,8 @@ describe('Dynamic zod schema', () => {
en: 'Test',
},
inputWidth: '12',
min: null,
max: null,
ofCollections: [uuid()],
isDisabled: false,
isRequired: true,
Expand Down

0 comments on commit c6368e4

Please sign in to comment.