instantdb-react-ui
Version:
Customizable react components for InstantDB (forms/lists/etc.)
168 lines (167 loc) • 5.69 kB
JavaScript
import { z } from 'zod';
import { generateZodEntitySchema } from '../utils/utils';
/**
* Maps InstantDB types to Zod types.
* Used when a instant field does not have a zod validator. Handles required/optional fields.
*/
function getDefaultSchema(attr) {
let baseSchema;
switch (attr.valueType) {
case 'string':
baseSchema = z.string();
break;
case 'number':
baseSchema = z.number();
break;
case 'boolean':
baseSchema = z.boolean();
break;
case 'date':
baseSchema = z.number(); // instantdb uses number for dates
break;
case 'json':
baseSchema = z.any();
break;
default:
baseSchema = z.string();
}
return attr.required ? baseSchema : baseSchema.optional();
}
/** The default value map used by getDefaultValueByType */
const DEFAULT_VALUES_BY_TYPE = {
boolean: false,
string: '',
number: 0,
date: () => Date.now(),
};
/**
* Creates default values for useForm's initialValues parameter
* Used when an instant field does not have a zod default
*/
function getDefaultValueByType(valueType) {
const defaultValue = DEFAULT_VALUES_BY_TYPE[valueType];
// Use empty string for for unknown types
if (defaultValue === undefined)
return '';
return typeof defaultValue === 'function' ? defaultValue() : defaultValue;
}
export function createIDBEntityZodSchema(schema, entityName) {
const entity = schema.entities[entityName];
const entityAttrs = entity.attrs;
const schemaObj = {};
const defaults = {};
// Handle attributes
Object.entries(entityAttrs).forEach(([key, attr]) => {
const attrSchema = attr.zodSchema;
let fieldSchema;
if (attrSchema) {
try {
fieldSchema = attrSchema;
// Extract default if it exists from Zod schema
if ('_def' in fieldSchema && 'defaultValue' in fieldSchema._def) {
const defaultValue = fieldSchema._def.defaultValue;
defaults[key] = typeof defaultValue === 'function' ? defaultValue() : defaultValue;
}
else {
defaults[key] = getDefaultValueByType(attr.valueType);
}
}
catch (e) {
fieldSchema = getDefaultSchema(attr);
defaults[key] = getDefaultValueByType(attr.valueType);
}
}
else {
fieldSchema = getDefaultSchema(attr);
defaults[key] = getDefaultValueByType(attr.valueType);
}
schemaObj[key] = fieldSchema;
});
// Handle links
Object.entries(entity.links).forEach(([key, link]) => {
const linkSchema = link.zodSchema;
if (link.cardinality === 'one') {
defaults[key] = null;
if (linkSchema) {
schemaObj[key] = linkSchema;
}
else {
schemaObj[key] = generateZodEntitySchema().nullable();
}
}
else {
defaults[key] = [];
if (linkSchema) {
schemaObj[key] = linkSchema;
}
else {
schemaObj[key] = z.array(generateZodEntitySchema().nullable());
}
}
});
return {
zodSchema: z.object(schemaObj),
defaults: defaults,
};
}
/** Creates a zod schema and default values for useForm's initialValues parameter */
export function internalCreateIDBEntityZodSchema(entity, links) {
const entityAttrs = entity.attrs;
const schemaObj = {};
const defaults = {};
Object.entries(entityAttrs).forEach(([key, attr]) => {
const attrSchema = attr.zodSchema;
let fieldSchema;
if (attrSchema) {
try {
fieldSchema = attrSchema;
// Extract default if it exists from Zod schema
if ('_def' in fieldSchema && 'defaultValue' in fieldSchema._def) {
const defaultValue = fieldSchema._def.defaultValue;
defaults[key] = typeof defaultValue === 'function' ? defaultValue() : defaultValue;
}
else {
// If no Zod default, use valueType default
defaults[key] = getDefaultValueByType(attr.valueType);
}
}
catch (e) {
// fallback to default schema
fieldSchema = getDefaultSchema(attr.valueType);
defaults[key] = getDefaultValueByType(attr.valueType);
}
}
else {
// fallback to default schema
fieldSchema = getDefaultSchema(attr.valueType);
defaults[key] = getDefaultValueByType(attr.valueType);
}
schemaObj[key] = fieldSchema;
});
// Add zod schema for links
Object.entries(links).forEach(([key, link]) => {
const linkSchema = link.zodSchema;
if (link.cardinality === 'one') {
defaults[key] = null;
if (linkSchema) {
schemaObj[key] = linkSchema;
}
else {
schemaObj[key] = generateZodEntitySchema().nullable();
}
}
else {
defaults[key] = [];
if (linkSchema) {
schemaObj[key] = linkSchema;
}
else {
schemaObj[key] = z.array(generateZodEntitySchema().nullable());
}
}
});
return {
zodSchema: z.object(schemaObj),
defaults,
};
}