Aller au contenu principal
Version: 1.9.0

Définir un schéma

Une propriété de schéma est considérée comme correctement définie lorsqu'elle est l'un des types de champs intégrés : une Constante, une Dépendante, une Lax, une Requise, une Virtuelle ou un Timestamp

N.B : Clean schema lèvera une erreur si une propriété n'est pas correctement définie. Le constructeur Schema accepte 2 arguments :

  1. definitions (obligatoire)
  2. options (optionnel)

Le constructeur de schéma prend également deux types génériques que vous pouvez utiliser pour améliorer l'inférence de types de vos données Input & Output.

const userSchema = new Schema<Input, Output>(definitions, options);
import { Schema } from "ivo";

type UserInput = {
dob: Date | null;
firstName: string;
lastName: string;
};

type User = {
dob: Date | null;
firstName: string;
lastName: string;
fullName: string;
};

const userSchema = new Schema<UserInput, User>({
dob: { required: true, validator: validateDob },
firstName: { required: true, validator: validateName },
lastName: { required: true, validator: validateName },
fullName: {
default: "",
dependsOn: ["firstName", "lastName"],
resolver({ ctx: { firstName, lastName } }) {
return `${firstName} ${lastName}`;
},
},
});

const UserModel = userSchema.getModel();

Propriétés d'un modèle

Ces méthodes sont asynchrones car les validateurs personnalisés peuvent également être asynchrones.

PropriétéTypeDescription
createfunctionMéthode asynchrone pour créer une instance
deletefunctionMéthode asynchrone pour déclencher tous les écouteurs onDelete
updatefunctionMéthode asynchrone pour mettre à jour une instance

Règles acceptées

PropriétéTypeDescription
allowany[ ] | objectutilisé pour spécifier les valeurs qui doivent être acceptées pour une propriété. En savoir plus
constantbooleanà utiliser avec la règle value pour spécifier une propriété avec une valeur constante. plus
defaultany | functionla valeur par défaut d'une propriété. plus
dependsOnstring | string[ ]une propriété ou une liste de propriétés dont dépend ladite propriété. plus
ignorefunctionune fonction utilisée pour déterminer si la valeur d'entrée d'une propriété doit être ignorée. Cela agit comme shouldInit + shouldUpdate
onDeletefunction | function[ ]exécuté lorsque la méthode delete d'un modèle est invoquée plus
onFailurefunction | function[ ]exécuté après une opération infructueuse plus
onSuccessfunction | function[ ]exécuté après une opération réussie plus
readonlyboolean | 'lax'une propriété dont la valeur ne doit pas changer plus
requiredboolean | functionune propriété qui doit être définie pendant une opération plus
sanitizerfunctionCela peut être utilisé pour transformer une propriété virtuelle avant que ses propriétés dépendantes ne soient résolues. plus
shouldInitfalse | function(): booleanUn booléen ou un setter qui indique à ivo si une propriété doit être initialisée ou non.
shouldUpdatefalse | function(): booleanUn booléen ou un setter qui indique à ivo si une propriété doit être initialisée ou non.
validatorfunctionUne fonction (async / sync) utilisée pour valider la valeur d'une propriété. plus
valueany | functionvaleur ou setter d'une propriété constante. plus
virtualbooleanune propriété d'assistance qui peut être utilisée pour fournir un contexte supplémentaire mais n'apparaît pas sur les instances de votre modèle plus

Options

import type { Context, IvoSummary, ReadonlyIvoSummary } from 'ivo';

type Input = {};
type Output = {};

type IContext = Context<Input, Output>;
type Summary = IvoSummary<Input, Output, CtxOptions>;

type DeleteListener = (data: Outpur, options: CtxOptions) => void | Promise<void>;

type SuccessListener = (summary: Summary) => void | Promise<void>

type Timestamp = {
createdAt?: string
updatedAt?: string
}

interface ErrorToolClass<ErrorTool, CtxOptions extends ObjectType> {
new (message: ValidationErrorMessage, ctxOptions: CtxOptions): ErrorTool;
}

type SchemaOptions = {
equalityDepth?: number
errorTool?: ErrorToolClass // more on this below 👇
onDelete?: DeleteListener | DeleteListener[]
onSuccess?: SuccessListener | SuccessListener[]
postValidate?: PostValidationConfig | PostValidationConfig[]
setMissingDefaultsOnUpdate?: boolean
shouldUpdate?: boolean | (summary: ISummary) => boolean
timestamps?: boolean | Timestamp
useParentOptions?: boolean // 👈 only for extended schemas
}

const options: SchemaOptions = {}

const schema = new Schema<Input, Output, CtxOptions, ErrorToolClass>(definitions, options)

Plus de détails sur les utilitaires Context & Summary peuvent être trouvés ici

equalityDepth (défaut : 1)

C'est le nombre utilisé pour déterminer si la valeur d'une propriété a changé pendant les mises à jour.

Pour déterminer si une propriété a changé, sa valeur est comparée à sa valeur par défaut et à sa valeur précédente. Comme l'égalité entre objets n'est pas toujours évidente, la valeur equalityDepth fournie est utilisée pour déterminer si les propriétés de votre schéma qui acceptent des objets (qui peuvent avoir des objets imbriqués) comme valeurs ont changé pendant les mises à jour.

Les valeurs possibles pour ce nombre vont de 0 à +Infinity. La valeur par défaut est 1, ce qui signifie un niveau d'imbrication.

Voici un extrait pour démontrer comment le simple changement d'arrangement des valeurs de propriétés imbriquées (sans même changer leurs valeurs réelles) peut affecter les résultats d'une mise à jour :

const user = {
name: "John Doe",
bio: {
facebook: { displayName: "john", handle: "john3434" },
twitter: { displayName: "John Doe", handle: "john_on_twitter" },
},
};

// depth == 0

Model.update(user, { bio: user.bio }).then(({ data, error }) => {
console.log(data); // null
console.log(error.message); // Nothing to update
});

// 👇 changing the positions of facebook & twitter in bio
Model.update(user, {
bio: {
twitter: { displayName: "John Doe", handle: "john_on_twitter" },
facebook: { displayName: "john", handle: "john3434" },
},
}).then(({ data, error }) => {
console.log(data);
// {
// bio: {
// facebook: { displayName: 'john', handle: 'john3434' },
// twitter: { displayName: 'John Doe', handle: 'john_on_twitter' }
// }
// }

console.log(error); // null
});

// depth == 1

Model.update(user, { bio: user.bio }).then(({ data, error }) => {
console.log(data); // null
console.log(error.message); // Nothing to update
});

// 👇 changing the positions of facebook & twitter in bio
Model.update(user, {
bio: {
twitter: { displayName: "John Doe", handle: "john_on_twitter" },
facebook: { displayName: "john", handle: "john3434" },
},
}).then(({ data, error }) => {
console.log(data); // null
console.log(error.message); // Nothing to update
});

// 👇 changing the positions of facebook & twitter in bio and the positions of displayName & handle
Model.update(user, {
bio: {
twitter: { handle: "john_on_twitter", displayName: "John Doe" },
facebook: { displayName: "john", handle: "john3434" },
},
}).then(({ data, error }) => {
console.log(data);
// {
// bio: {
// facebook: { displayName: 'john', handle: 'john3434' },
// twitter: { handle: 'john_on_twitter', displayName: 'John Doe' }
// }
// }

console.log(error); // null
});

errorTool

C'est une classe qui sera utilisée pour gérer vos erreurs de validation, vous donnant ainsi le pouvoir d'avoir des erreurs de validation personnalisées. Voir l'exemple ici

import type { ValidationErrorMessage, IErrorTool } from "ivo";

// the class should have this signature 👇
interface ErrorToolClass<ErrorTool, CtxOptions extends ObjectType> {
new (message: ValidationErrorMessage, ctxOptions: CtxOptions): ErrorTool;
}

// the instances of your ErrorTool class should have this signature 👇
interface IErrorTool<ExtraData extends ObjectType = {}> {
/** return what your validation error should look like from this method */
get data(): IValidationError<ExtraData>;

/** array of fields that have failed validation */
get fields(): string[];

/** determines if validation has failed */
get isLoaded(): boolean;

/** used to append a field to your final validation error */
set(field: FieldKey, error: FieldError, value?: any): this;

/** method to set the value of the validation error message */
setMessage(message: ValidationErrorMessage): this;
}

type IValidationError<ExtraData extends ObjectType = {}> = ({
message: ValidationErrorMessage;
} & ExtraData) & {};

onDelete

Cela peut être une fonction ou un tableau de fonctions avec la signature DeleteListener ci-dessus. Ces fonctions seront déclenchées en même temps que les écouteurs onDelete des propriétés individuelles lorsque la méthode Model.delete est invoquée. En savoir plus ici

onSuccess

Cela peut être une fonction ou un tableau de fonctions avec la signature SuccessListener ci-dessus. Ces fonctions seront déclenchées en même temps que les écouteurs onSuccess des propriétés individuelles lorsque la méthode handleSuccess est invoquée lors de la création et pendant les mises à jour de toute propriété. En savoir plus ici

postValidate

Pour valider l'intégrité de plusieurs champs après la validation initiale. Plus d'informations ici

setMissingDefaultsOnUpdate

Un booléen. S'il est défini sur true, il vérifiera toutes les propriétés pouvant avoir une valeur par défaut des données existantes passées à la méthode de mise à jour du modèle Model.update(existingData, updates), et pour toutes les propriétés ayant la valeur undefined, il générera leurs valeurs par défaut, les ajoutera au contexte de l'opération avant de valider les mises à jour fournies.

Si l'opération de mise à jour réussit, les valeurs par défaut nouvellement générées seront également ajoutées aux valeurs mises à jour retournées si elles ne sont pas déjà présentes dans les valeurs mises à jour. Valeur par défaut false

shouldUpdate (défaut : true)

Un booléen ou une fonction qui attend le résumé de l'opération et retourne une valeur booléenne. Cette valeur est lue/calculée avant que les valeurs fournies pendant les mises à jour aient été validées.

Si sa valeur ou sa valeur calculée est true, les validations des mises à jour se poursuivront, sinon l'opération échouera avec le message d'erreur Nothing to update

new Schema(
{ id: { constant: true, value: generateId } },
{ shouldUpdate: () => (condition ? true : false) },
);

timestamps (défaut : false)

Si timestamps est défini sur true, vous aurez automatiquement les propriétés createdAt et updatedAt attachées aux instances de votre modèle lors de la création et pendant la mise à jour. Mais vous pouvez remplacer les options et utiliser vos propres propriétés comme dans l'exemple ci-dessous. Valeur par défaut false

Remplacer une seule

let transactionSchema = new Schema(definitions, {
timestamps: { createdAt: "created_at" },
});

Ou les deux

let transactionSchema = new Schema(definitions, {
timestamps: { createdAt: "created_at", updatedAt: "updated_at" },
});

Pour utiliser un seul timestamp, passez false pour la clé du timestamp à éliminer

let transactionSchema = new Schema(definitions, {
timestamps: { createdAt: "created_at", updatedAt: false },
});

// or
let transactionSchema = new Schema(definitions, {
timestamps: { updatedAt: false },
});

À partir de la v1.6.1, updated_at est null à la création

// make updatedAt non-nullable
let transactionSchema = new Schema(definitions, {
timestamps: { updatedAt: { key: "updated_at", nullable: false } },
});

// or non-nullable whilte keeping the default key
let transactionSchema = new Schema(definitions, {
timestamps: { updatedAt: { nullable: false } },
});

useParentOptions (défaut : true)

Lors de l'extension de schémas, les schémas étendus héritent automatiquement de toutes les options (sauf les méthodes de cycle de vie) du schéma de base. Définir useParentOptions: false dans les options du schéma étendu empêchera ce comportement. La valeur par défaut est true

Essayez-le dans le navigateur

Loading playground…