Time Validation
Time validation allows you to define constraints for entities that have time-based attributes like from and to dates. This is useful for scenarios like contracts, subscriptions, bookings, or any entity where time periods should not overlap and optionally must be consecutive.
Configuration
timeValidation?: {
from: string; // path to the start date attribute
to: string; // path to the end date attribute
scope?: string | string[]; // attributes that define the scope for validation
consecutive?: boolean; // if true, periods must be consecutive without gaps
}| Option | Type | Default | Description |
|---|---|---|---|
from | string | Name of the attribute containing the start date/time | |
to | string | Name of the attribute containing the end date/time | |
scope | string | string[] | undefined | Fields (attribute or foreignKey) that define the scope within which validation applies; if undefined or [] the scope is all entity items |
consecutive | boolean | false | If true, time periods must be consecutive (no gaps allowed) |
Validation Rules
The timeValidation configuration enforces the following rules:
1. From Before To
The from date must always be before the to date for the same entity item.
2. No Overlap
Time periods within the same scope must not overlap. This prevents conflicting entries like two contracts for the same customer being active at the same time.
3. Consecutive Periods (optional)
When consecutive: true is set, time periods must directly follow each other without gaps. The validation checks:
- The new period's start must be consecutive to the previous period's end
- The new period's end must be consecutive to the next period's start
For date-only values (no time component), "consecutive" means a difference of 1 day. For datetime values, it means a difference of 1 second.
Example
Basic Usage
entity:
Contract:
attributes:
customerId: string!
validFrom: date!
validTo: date!
description: string
timeValidation:
from: validFrom
to: validTo
scope: customerIdIn this example:
- Each contract has a validity period (
validFromtovalidTo) - Contracts for the same customer (
scope: customerId) cannot overlap - Different customers can have overlapping contracts
With Consecutive Requirement
entity:
Subscription:
attributes:
userId: string!
planType: string!
startDate: date!
endDate: date!
timeValidation:
from: startDate
to: endDate
scope:
- userId
- planType
consecutive: trueIn this example:
- Subscriptions for the same user and plan type cannot overlap
- Subscription periods must be consecutive (no gaps allowed)
- A new subscription must start exactly one day after the previous one ends
TypeScript Configuration
export const domainConfiguration: DomainConfiguration = {
entity: {
Booking: {
attributes: {
roomId: 'string!',
checkIn: 'date!',
checkOut: 'date!',
guestName: 'string!'
},
timeValidation: {
from: 'checkIn',
to: 'checkOut',
scope: 'roomId'
}
}
}
}Validation Messages
When validation fails, the following messages are returned:
| Violation | Message | Path |
|---|---|---|
| From date is not before to date | {from} must be before {to} | from attribute |
| Time period overlaps with existing | No overlap allowed | Affected attribute (from or to) |
| Gap before next period | Must be consecutive to next start | to attribute |
| Gap after previous period | Must be consecutive to previous end | from attribute |
GraphQL Response Example
Request
mutation {
createContract(
contract: {
customerId: "123"
validFrom: "2024-01-01"
validTo: "2024-06-30"
}
) {
contract { id validFrom validTo }
validationViolations { path message }
}
}Response with validation error (overlap)
{
"data": {
"createContract": {
"contract": null,
"validationViolations": [
{
"path": "validFrom",
"message": "No overlap allowed"
}
]
}
}
}Response with validation error (from after to)
{
"data": {
"createContract": {
"contract": null,
"validationViolations": [
{
"path": "validFrom",
"message": "validFrom must be before validTo"
}
]
}
}
}Use Cases
Employment Contracts
Ensure an employee doesn't have overlapping employment periods:
timeValidation:
from: startDate
to: endDate
scope: employeeIdRoom Bookings
Prevent double-booking of rooms:
timeValidation:
from: checkIn
to: checkOut
scope: roomIdInsurance Policies
Ensure consecutive coverage without gaps:
timeValidation:
from: effectiveFrom
to: effectiveTo
scope: policyHolderId
consecutive: trueRental Agreements
Track rental periods per item:
timeValidation:
from: rentalStart
to: rentalEnd
scope:
- itemId
- locationId