Skip to content

Commit bee641e

Browse files
committed
feat: add date validation rules
1 parent 70d24fc commit bee641e

File tree

3 files changed

+134
-114
lines changed

3 files changed

+134
-114
lines changed

content/docs/db.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@
6565
"contentPath": "./types/number.md",
6666
"category": "Schema types"
6767
},
68+
{
69+
"permalink": "types/date",
70+
"title": "Date",
71+
"contentPath": "./types/date.md",
72+
"category": "Schema types"
73+
},
6874
{
6975
"permalink": "types/accepted",
7076
"title": "Accepted",

content/docs/types/date.md

Lines changed: 127 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,203 +1,217 @@
11
# Date type
22

3-
The date schema type validates the field's value to be a string formatted as a date. The output get's converted to an instance of [Luxon DateTime](https://moment.github.io/luxon/api-docs/index.html#datetime) class.
3+
Ensure the field's value is a string formatted as a date or datetime per the expected formats. The return value is an instance of the [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) class.
44

5-
To use the `vine.date` method, you must install [luxon](https://moment.github.io/luxon/#/install) as your project dependency.
5+
```ts
6+
import vine from '@vinejs/vine'
67

7-
```sh
8-
npm i luxon
8+
const schema = vine.object({
9+
published_at: vine.date()
10+
})
911
```
1012

11-
Once installed, you may use the date schema type as follows.
13+
By default, the input value should be formatted as a `YYYY-MM-DD` or `YYYY-MM-DD HH:mm:ss` string. However, you may define custom formats as well. In the following example, we expect the input string to be valid per any of the mentioned formats.
14+
15+
:::note
16+
17+
You must check the Day.js documentation to [view the available formatting tokens](https://day.js.org/docs/en/parse/string-format#list-of-all-available-parsing-tokens).
18+
19+
:::
1220

1321
```ts
1422
import vine from '@vinejs/vine'
1523

1624
const schema = vine.object({
17-
dob: vine.date(),
25+
published_at: vine.date({
26+
formats: ['YYYY/DD/MM', 'x']
27+
})
1828
})
19-
20-
const data = {
21-
dob: '1990-05-23'
22-
}
23-
24-
const output = await vine.validate({ schema, data })
25-
26-
output.dob // DateTime
2729
```
2830

29-
## Defining format and zone
31+
You may mark the field as `optional` or `nullable` using the following modifiers.
3032

31-
The date values are validated against the `ISO` format by default. However, using the `format` option, you may define a custom format.
33+
See also: [Working with `undefined` and `null` values](../guides/schema_101.md#nullable-and-optional-modifiers)
3234

3335
```ts
34-
vine.date({ format: 'iso' })
35-
vine.date({ format: 'sql' })
36-
vine.date({ format: 'yyyy-MM-dd HH:mm:ss' })
36+
{
37+
published_at: vine.date().nullable()
38+
}
3739
```
3840

39-
You may use the following shorthand keywords or use any available [Luxon DateTime tokens](https://moment.github.io/luxon/#/parsing?id=table-of-tokens) to define the format.
41+
```ts
42+
{
43+
published_at: vine.date().optional()
44+
}
45+
```
4046

41-
- `iso`
42-
- `sql`
43-
- `rfc2822`
44-
- `http`
4547

46-
Post validation, the DateTime instance is created in the local timezone of your server. However, you may [define an explicit zone](https://moment.github.io/luxon/#/zones?id=creating-datetimes-in-a-zone) using the `zone` property.
48+
## Defining error message
49+
You may define custom error messages for the following date-based rules.
4750

4851
```ts
49-
vine.date({
50-
zone: 'utc'
51-
})
52+
const messages = {
53+
'date': 'The {{ field }} field must be a datetime value',
54+
55+
'date.equals': 'The {{ field }} field must be a date equal to {{ expectedValue }}',
56+
'date.after': 'The {{ field }} field must be a date after {{ expectedValue }}',
57+
'date.before': 'The {{ field }} field must be a date before {{ expectedValue }}',
58+
'date.afterOrEqual': 'The {{ field }} field must be a date after or equal to {{ expectedValue }}',
59+
'date.beforeOrEqual': 'The {{ field }} field must be a date before or equal to {{ expectedValue }}',
60+
61+
'date.sameAs': 'The {{ field }} field and {{ otherField }} field must be the same',
62+
'date.notSameAs': 'The {{ field }} field and {{ otherField }} field must be different',
63+
'date.afterField': 'The {{ field }} field must be a date after {{ otherField }}',
64+
}
65+
66+
vine.messagesProvider = new SimpleMessagesProvider(messages)
5267
```
5368

54-
## Validations
69+
## Comparing dates
70+
You may use one of the following validation methods to compare the user input against a specific datetime value.
71+
72+
- `equals`: Ensure the input datetime value is the same as the expected datetime value.
5573

56-
Following is the list of validation rules you may apply on a date.
74+
- `after`: Ensure the input datetime value is after the expected datetime value.
5775

58-
### equals
59-
Ensure the value of date is same as the pre-defined value. The expected value must be an instance of the Luxon DateTime class.
76+
- `afterOrEqual`: Same as the `after` method, but performs a greater than and equal to comparison.
77+
78+
- `before`: Ensure the input datetime value is before the expected datetime value.
79+
80+
- `beforeOrEqual`: Same as the `before` method, but performs a less than and equal to comparison.
6081

6182
```ts
83+
// title: Example of equals
6284
const schema = vine.object({
6385
enrollment_date: vine
6486
.date()
65-
.equals(DateTime.fromISO('2023-05-25'))
87+
.equals('2024-01-28')
6688
})
6789
```
6890

69-
### notEquals
70-
Ensure the value of date is not same as the pre-defined value. The expected value must be an instance of the Luxon DateTime class.
71-
7291
```ts
92+
// title: Example of after
7393
const schema = vine.object({
74-
enrollment_date: vine
94+
checkin_date: vine
7595
.date()
76-
.notEquals(DateTime.fromISO('2023-05-25'))
96+
.after('today')
7797
})
78-
```
79-
80-
### sameAs
8198

82-
### notSameAs
83-
84-
### after / afterOrEqual
99+
const schema = vine.object({
100+
checkin_date: vine
101+
.date()
102+
.after('2024-01-01')
103+
})
104+
```
85105

86-
Ensure the date is after a given interval. The `after` and `afterOrEqual` methods accepts the interval as the `first` argument and the unit as the `second` argument.
106+
When using dynamic or computed values, you must use a callback function. Otherwise, the initial value will be cached forever with a [precompiled schema](../guides/getting_started.md#pre-compiling-schema).
87107

88108
```ts
109+
// title: Lazily compute the expected value
89110
const schema = vine.object({
90-
checkin_date: vine
111+
enrollment_date: vine
91112
.date()
92-
.after(2, 'days')
113+
// highlight-start
114+
.afterOrEqual((field) => {
115+
return dayjs().add(2, 'day').format('YYYY-MM-DD')
116+
})
117+
// highlight-end
93118
})
94119
```
95120

96-
Following is the list of available units.
121+
### How is the comparison performed?
122+
Validation rules use the `compare` unit to compare the two dates. By default, the compare unit is set to `day`, which means the validation will compare the `day`, `month`, and the `year` values.
123+
124+
Similarly, if you set the compare unit to `minutes`, the validation will compare `minutes`, `hours`, `day`, `month` and the `year`.
125+
126+
:::tip
127+
128+
Under the hood, the comparison is performed using the [Days.js query methods](https://day.js.org/docs/en/query/is-before).
129+
130+
:::
97131

98132
```ts
99-
vine.date().after(2, 'days')
100-
vine.date().after(1, 'month')
101-
vine.date().after(3, 'years')
102-
vine.date().after(30, 'minutes')
103-
vine.date().after(2, 'quarters')
133+
vine
134+
.date()
135+
.equals('2024-01-28', {
136+
compare: 'month', // compares month and the year
137+
})
104138
```
105139

106-
For advanced use cases, you may pass an instance of the Luxon DateTime directly.
140+
### Using a custom format
141+
Validation rules assume the expected datetime format to be an ISO string. However, you may use the `format` option to specify a custom format.
107142

108143
```ts
109144
vine
110145
.date()
111-
.after(DateTime.utc(), 'days')
146+
.equals('2024/28/01', {
147+
format: 'YYYY/DD/MM',
148+
})
112149
```
113150

114-
### afterField / afterOrSameAsField
151+
## Comparing against other fields
152+
Alongside performing [comparison against a fixed datetime value](#comparing-dates), you may also use the following validation methods to compare the input value against the value of another field.
115153

116-
The `afterField` and `afterOrSameAsField` methods enforce the date to be after the date value of the other field.
154+
- `sameAs`: Ensure the input datetime value is the same as the other field's value.
117155

118-
The `afterField` validation is skipped when the other field's value is not a valid date.
156+
- `notSameAs`: Ensure the input datetime value is not the same as the other field's value.
119157

120-
```ts
121-
const schema = vine.object({
122-
checkin_date: vine.date().inFuture({ unit: 'days' }),
123-
checkout_date: vine
124-
.date()
125-
.afterField('checkin_date'),
126-
})
127-
```
158+
- `afterField`: Ensure the input datetime value is after the other field's value.
159+
160+
- `afterOrSameAs`: Same as the `afterField` rule, but performs a greater than and equal to comparison.
128161

129-
By default, the diff between two dates is calculated in minutes. However, you may define a custom diff unit via the options object.
162+
- `beforeField`: Ensure the input datetime value is before the other field's value.
163+
164+
- `beforeOrSameAs`: Same as the `beforeField` rule, but performs a less than and equal to comparison.
130165

131166
```ts
167+
// title: Example of sameAs
132168
const schema = vine.object({
133-
checkin_date: vine.date().inFuture({ unit: 'days' }),
134-
checkout_date: vine
135-
.date()
136-
.afterField('checkin_date', { unit: 'days' }),
169+
entry_date: vine.date(),
170+
exit_date: vine.date().sameAs('entry_date')
137171
})
138172
```
139173

140-
141-
### before / beforeOrEqual
142-
143-
Ensure the date is before a given interval. The `before` and `beforeOrEqual` methods accept the interval as the `first` argument and the unit as the `second` argument.
144-
145174
```ts
175+
// title: Example of afterField
146176
const schema = vine.object({
147-
dob: vine
148-
.date()
149-
.before(10, 'years')
177+
checkin_date: vine.date(),
178+
checkout_date: vine.date().afterField('checkin_date')
150179
})
151180
```
152181

153-
Following is the list of available units.
154-
155-
```ts
156-
vine.date().before(2, 'days')
157-
vine.date().before(1, 'month')
158-
vine.date().before(3, 'years')
159-
vine.date().before(30, 'minutes')
160-
vine.date().before(2, 'quarters')
161-
```
182+
You may specify the comparison unit and the format of the other field using the options object.
162183

163-
For advanced use cases, you may pass an instance of the Luxon DateTime directly.
184+
See also: [How is the comparison performed?](#how-is-the-comparison-performed)
164185

165186
```ts
166-
vine
167-
.date()
168-
.before(DateTime.utc().minus({ days: 1 }))
187+
const schema = vine.object({
188+
checkin_date: vine.date({
189+
formats: ['YYYY/MM/DD']
190+
}),
191+
checkout_date: vine.date().afterField('checkin_date', {
192+
compare: 'day',
193+
format: ['YYYY/MM/DD']
194+
})
195+
})
169196
```
170197

171-
### beforeField / beforeOrSameAsField
198+
## Other validation rules
199+
Following is the list of other (non-comparison) validation rules.
172200

173-
The `beforeField` and `beforeOrSameAsField` methods enforce the date to be before the date value of the other field.
174-
175-
The `beforeField` validation is skipped when the other field's value is not a valid date.
201+
### weekend
202+
Ensure the date is a weekend.
176203

177204
```ts
178205
const schema = vine.object({
179-
checkin_date: vine.date(),
180-
documents_approved_at: vine
181-
.date()
182-
.beforeField('checkin_date')
206+
checkin_date: vine.date().weekend()
183207
})
184208
```
185209

186-
By default, the diff between two dates is calculated in minutes. However, you may define a custom diff unit via the options object.
210+
### weekday
211+
Ensure the date is a weekday.
187212

188213
```ts
189214
const schema = vine.object({
190-
checkin_date: vine.date(),
191-
documents_approved_at: vine
192-
.date()
193-
.beforeField('checkin_date', { unit: 'days' })
215+
event_date: vine.date().weekday()
194216
})
195217
```
196-
197-
### inFuture
198-
199-
### inPast
200-
201-
### weekday
202-
203-
### weekend

src/collections.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const docs = new Collection()
1717
.useRenderer(renderer)
1818
.urlPrefix('/docs')
1919
.tap((entry) => {
20-
entry.setMarkdownOptions({ tocDepth: 2 })
20+
entry.setMarkdownOptions({ tocDepth: 3 })
2121
})
2222

2323
await docs.boot()

0 commit comments

Comments
 (0)