@orieljs/framework 0.1.0-alpha.1 → 0.1.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +7 -0
- package/README.md +10 -1
- package/TRADEMARKS.md +33 -0
- package/dist/chunk-7ZQZYDOC.js +3253 -0
- package/dist/chunk-7ZQZYDOC.js.map +1 -0
- package/dist/{chunk-K6MAA3RM.js → chunk-GVNLZZTN.js} +7 -1
- package/dist/chunk-GVNLZZTN.js.map +1 -0
- package/dist/chunk-OXAATQA6.js +8433 -0
- package/dist/chunk-OXAATQA6.js.map +1 -0
- package/dist/{chunk-WI7E7Q46.js → chunk-VOYW3R5J.js} +8 -4
- package/dist/chunk-VOYW3R5J.js.map +1 -0
- package/dist/contracts.d.ts +841 -168
- package/dist/contracts.js +7 -1
- package/dist/index.d-WQpfdIbG.d.ts +630 -0
- package/dist/index.d.ts +2916 -5178
- package/dist/index.js +7357 -2609
- package/dist/index.js.map +1 -1
- package/dist/{jsx-runtime-B8J6xq-7.d.ts → jsx-runtime-6um4Mwfb.d.ts} +99 -149
- package/dist/jsx-runtime.d.ts +3 -1
- package/dist/jsx-runtime.js +3 -3
- package/dist/testing-CKwfWJGn.d.ts +1586 -0
- package/dist/testing.d.ts +3 -1408
- package/dist/testing.js +29 -5
- package/docs/authentication.md +487 -0
- package/docs/authorization.md +435 -0
- package/docs/cache.md +647 -0
- package/docs/collections.md +2270 -0
- package/docs/configuration.md +334 -0
- package/docs/console.md +652 -0
- package/docs/container.md +430 -0
- package/docs/controllers.md +406 -0
- package/docs/csrf.md +126 -0
- package/docs/database-testing.md +144 -0
- package/docs/database.md +236 -0
- package/docs/deployment.md +276 -0
- package/docs/eloquent-collections.md +218 -0
- package/docs/eloquent-factories.md +255 -0
- package/docs/eloquent-mutators.md +254 -0
- package/docs/eloquent-observers.md +145 -0
- package/docs/eloquent-relationships.md +557 -0
- package/docs/eloquent.md +494 -0
- package/docs/encryption.md +104 -0
- package/docs/errors.md +318 -0
- package/docs/events.md +336 -0
- package/docs/facades.md +278 -0
- package/docs/hashing.md +118 -0
- package/docs/helpers.md +1281 -0
- package/docs/http-tests.md +386 -0
- package/docs/inertia.md +485 -0
- package/docs/installation.md +209 -0
- package/docs/lifecycle.md +234 -0
- package/docs/live-tests.md +226 -0
- package/docs/live.md +910 -0
- package/docs/logging.md +255 -0
- package/docs/mail.md +619 -0
- package/docs/middleware.md +384 -0
- package/docs/migrations.md +416 -0
- package/docs/mocking.md +264 -0
- package/docs/navigation.json +273 -0
- package/docs/notifications.md +225 -0
- package/docs/pagination.md +247 -0
- package/docs/passwords.md +207 -0
- package/docs/providers.md +187 -0
- package/docs/queries.md +600 -0
- package/docs/queues.md +330 -0
- package/docs/requests.md +533 -0
- package/docs/responses.md +444 -0
- package/docs/routing.md +738 -0
- package/docs/scheduling.md +277 -0
- package/docs/seeding.md +122 -0
- package/docs/session.md +409 -0
- package/docs/starter-kits.md +396 -0
- package/docs/storage.md +192 -0
- package/docs/structure.md +264 -0
- package/docs/testing.md +165 -0
- package/docs/time-travel.md +138 -0
- package/docs/validation.md +1792 -0
- package/docs/verification.md +152 -0
- package/docs/views.md +566 -0
- package/docs/vite.md +322 -0
- package/package.json +35 -30
- package/dist/chunk-AI2RFMBT.js +0 -745
- package/dist/chunk-AI2RFMBT.js.map +0 -1
- package/dist/chunk-BZPCRKFQ.js +0 -2941
- package/dist/chunk-BZPCRKFQ.js.map +0 -1
- package/dist/chunk-K6MAA3RM.js.map +0 -1
- package/dist/chunk-WI7E7Q46.js.map +0 -1
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Task scheduling
|
|
2
|
+
|
|
3
|
+
The scheduler runs your app's recurring tasks: you define them in your code, and one cron entry on your server runs
|
|
4
|
+
them all.
|
|
5
|
+
|
|
6
|
+
## Introduction
|
|
7
|
+
|
|
8
|
+
Apps once needed a cron entry for every task. Oriel's scheduler, as Laravel's, keeps the whole schedule in your code, in
|
|
9
|
+
`routes/console.ts`, so it is in your repository with the rest of your app. Your server needs one cron entry, which runs
|
|
10
|
+
`schedule:run` every minute (see [Running the scheduler](#running-the-scheduler)).
|
|
11
|
+
|
|
12
|
+
## Defining schedules
|
|
13
|
+
|
|
14
|
+
Define your tasks with the `Schedule` facade, in `routes/console.ts`. This one empties a table every day at midnight:
|
|
15
|
+
|
|
16
|
+
```ts title="routes/console.ts"
|
|
17
|
+
import { DB, Schedule } from '@orieljs/framework'
|
|
18
|
+
|
|
19
|
+
Schedule.call(async () => {
|
|
20
|
+
await DB.table('recent_users').delete()
|
|
21
|
+
}).daily()
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
A task is a console command, a closure or a job. `node oriel schedule:list` lists the tasks you have defined, each
|
|
25
|
+
with its cron expression.
|
|
26
|
+
|
|
27
|
+
### Scheduling commands
|
|
28
|
+
|
|
29
|
+
`Schedule.command()` runs a console command by its name, with its arguments and options in an array, or written into
|
|
30
|
+
the name:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
Schedule.command('emails:send', ['taylor', '--force']).daily()
|
|
34
|
+
|
|
35
|
+
Schedule.command('emails:send taylor --force').daily()
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
A command fails when it ends with an exit code other than 0.
|
|
39
|
+
|
|
40
|
+
> [!NOTE]
|
|
41
|
+
> Laravel runs each scheduled Artisan command in a PHP process of its own. Oriel runs it in the `schedule:run`
|
|
42
|
+
> process, through your app's console kernel, as `Artisan.call()` does: there is no process to start, and your
|
|
43
|
+
> commands share that process with the other tasks.
|
|
44
|
+
|
|
45
|
+
### Scheduling closures
|
|
46
|
+
|
|
47
|
+
`Schedule.call()` runs a function, which may be async, as in the [example above](#defining-schedules). It fails when
|
|
48
|
+
it throws, or returns `false`.
|
|
49
|
+
|
|
50
|
+
### Scheduling queued jobs
|
|
51
|
+
|
|
52
|
+
`Schedule.job()` takes a job, and the queue and the connection to push it onto:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
// @filename: app/Jobs/Heartbeat.ts
|
|
56
|
+
import { Queueable } from '@orieljs/framework'
|
|
57
|
+
export class Heartbeat extends Queueable {
|
|
58
|
+
async handle(): Promise<void> {}
|
|
59
|
+
}
|
|
60
|
+
// ---cut---
|
|
61
|
+
import { Heartbeat } from './app/Jobs/Heartbeat'
|
|
62
|
+
|
|
63
|
+
Schedule.job(new Heartbeat(), 'heartbeats', 'redis').everyFiveMinutes()
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The job is made when `routes/console.ts` loads, which is on every `node oriel` command, so don't read the database to
|
|
67
|
+
make it: a job that needs a model finds it in its `handle()`.
|
|
68
|
+
|
|
69
|
+
A queued job, such as one that extends `Queueable`, is pushed onto its queue each time the task runs, and a worker runs
|
|
70
|
+
it. Any other job runs at once, in the scheduler's process.
|
|
71
|
+
|
|
72
|
+
> [!NOTE]
|
|
73
|
+
> A job that runs in the scheduler's process fails, as a closure does, when its `handle()` returns `false`. Laravel's
|
|
74
|
+
> `Schedule::job()` doesn't look at what the job returns.
|
|
75
|
+
|
|
76
|
+
### Schedule frequency options
|
|
77
|
+
|
|
78
|
+
A task's frequency is a method on it:
|
|
79
|
+
|
|
80
|
+
| Method | Runs the task |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| `cron('* * * * *')` | On a cron expression of your own |
|
|
83
|
+
| `everySecond()`, `everyTwoSeconds()`, `everyFiveSeconds()`, `everyTenSeconds()`, `everyFifteenSeconds()`, `everyTwentySeconds()`, `everyThirtySeconds()` | Every second, or every 2, 5, 10, 15, 20 or 30 seconds (see [Sub-minute tasks](#sub-minute-tasks)) |
|
|
84
|
+
| `everyMinute()` | Every minute |
|
|
85
|
+
| `everyTwoMinutes()`, `everyThreeMinutes()`, `everyFourMinutes()`, `everyFiveMinutes()`, `everyTenMinutes()`, `everyFifteenMinutes()`, `everyThirtyMinutes()` | Every 2, 3, 4, 5, 10, 15 or 30 minutes |
|
|
86
|
+
| `hourly()` | Every hour, on the hour |
|
|
87
|
+
| `hourlyAt(17)` | Every hour at 17 minutes past (or a list of minutes: `hourlyAt([0, 30])`) |
|
|
88
|
+
| `everyOddHour(minute)`, `everyTwoHours(minute)`, `everyThreeHours(minute)`, `everyFourHours(minute)`, `everySixHours(minute)` | Every odd hour, or every 2, 3, 4 or 6 hours, at `minute` past (0 when left out) |
|
|
89
|
+
| `daily()` | Every day at midnight |
|
|
90
|
+
| `dailyAt('13:00')`, `at('13:00')` | Every day at 13:00 |
|
|
91
|
+
| `twiceDaily(1, 13)` | Every day at 1:00 and 13:00 |
|
|
92
|
+
| `twiceDailyAt(1, 13, 15)` | Every day at 1:15 and 13:15 |
|
|
93
|
+
| `weekly()` | Every Sunday at 00:00 |
|
|
94
|
+
| `weeklyOn(1, '8:00')` | Every week on Monday at 8:00 (or a list of days) |
|
|
95
|
+
| `monthly()` | On the first day of every month at 00:00 |
|
|
96
|
+
| `monthlyOn(4, '15:00')` | Every month on the 4th at 15:00 |
|
|
97
|
+
| `twiceMonthly(1, 16, '13:00')` | Every month on the 1st and the 16th at 13:00 |
|
|
98
|
+
| `lastDayOfMonth('15:00')` | On the last day of every month at 15:00 |
|
|
99
|
+
| `quarterly()` | On the first day of every quarter at 00:00 |
|
|
100
|
+
| `quarterlyOn(4, '14:00')` | Every quarter on the 4th at 14:00 |
|
|
101
|
+
| `yearly()` | On the first day of every year at 00:00 |
|
|
102
|
+
| `yearlyOn(6, 1, '17:00')` | Every year on June 1st at 17:00 |
|
|
103
|
+
|
|
104
|
+
Combine a frequency with the constraints below to narrow it, such as a task that runs every hour on weekdays:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
Schedule.command('reports:send').weekdays().hourly()
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Day constraints
|
|
111
|
+
|
|
112
|
+
`weekdays()`, `weekends()`, `mondays()`, `tuesdays()`, `wednesdays()`, `thursdays()`, `fridays()`, `saturdays()` and
|
|
113
|
+
`sundays()` limit a task to those days. `days()` takes the days as numbers, with 0 for Sunday:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
Schedule.command('emails:send').hourly().days(0, 3)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### Between time constraints
|
|
120
|
+
|
|
121
|
+
`between()` runs a task only between two times of day, and `unlessBetween()` only outside them. A window may cross
|
|
122
|
+
midnight:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
Schedule.command('emails:send').hourly().between('7:00', '22:00')
|
|
126
|
+
|
|
127
|
+
Schedule.command('emails:send').hourly().unlessBetween('23:00', '4:00')
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Truth test constraints
|
|
131
|
+
|
|
132
|
+
`when()` runs a task only when its function returns `true`, and `skip()` skips it when its function returns `true`.
|
|
133
|
+
The function may be async:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
Schedule.command('emails:send').daily().when(() => true)
|
|
137
|
+
|
|
138
|
+
Schedule.command('emails:send').daily().skip(async () => (await DB.table('jobs').count()) > 1000)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### Environment constraints
|
|
142
|
+
|
|
143
|
+
Laravel's `environments()` isn't in Oriel. Give `when()` the check instead:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
Schedule.command('emails:send').daily().when(() => app().environment('staging', 'production'))
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Timezones
|
|
150
|
+
|
|
151
|
+
A task's times are read in your app's timezone, `timezone` in `config/app.ts`, which is UTC in a new app.
|
|
152
|
+
`timezone()` sets another for one task:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
Schedule.command('report:generate').timezone('America/New_York').at('2:00')
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Preventing task overlaps
|
|
159
|
+
|
|
160
|
+
A task runs again when it is due, even if its last run hasn't finished. `withoutOverlapping()` skips a run while the
|
|
161
|
+
last one is still going:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
Schedule.command('emails:send').everyMinute().withoutOverlapping()
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The task holds a cache lock while it runs. In case a run never ends, the lock expires after 24 hours, or after the
|
|
168
|
+
number of minutes you give: `withoutOverlapping(10)`. `node oriel schedule:clear-cache` deletes the locks of the tasks
|
|
169
|
+
that use it, so a task stuck behind a run that was killed runs again.
|
|
170
|
+
|
|
171
|
+
A closure has no command to tell it apart from the others, so it needs a name first, or `withoutOverlapping()` throws
|
|
172
|
+
"A scheduled event name is required to prevent overlapping. Use the 'name' method before 'withoutOverlapping'.":
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
Schedule.call(async () => {
|
|
176
|
+
await DB.table('recent_users').delete()
|
|
177
|
+
})
|
|
178
|
+
.daily()
|
|
179
|
+
.name('prune-recent-users')
|
|
180
|
+
.withoutOverlapping()
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
A job is named after its class, so it needs no `name()`.
|
|
184
|
+
|
|
185
|
+
### Running tasks on one server
|
|
186
|
+
|
|
187
|
+
When your app runs the scheduler on several servers, `onOneServer()` runs a task on only one of them each time it is
|
|
188
|
+
due: the first server to take its lock runs it. The lock is in your default cache store, so every server must share
|
|
189
|
+
that store, as the `database` store does with a shared database, or the `redis` store with a shared Redis. A closure
|
|
190
|
+
needs a `name()` here too.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
Schedule.command('report:generate').fridays().at('17:00').onOneServer()
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Background tasks
|
|
197
|
+
|
|
198
|
+
The tasks due at the same time run one after the other. `runInBackground()` starts a task and goes on with the next
|
|
199
|
+
one without waiting for it, so a long task doesn't hold the others back. `schedule:run` still waits for it before it
|
|
200
|
+
ends:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
Schedule.command('analytics:report').daily().runInBackground()
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
> [!NOTE]
|
|
207
|
+
> Laravel's scheduler can also run shell commands (`exec()`), group tasks, keep running in maintenance mode, write or
|
|
208
|
+
> mail a task's output, ping URLs and dispatch scheduling events. Oriel's has none of these: run a shell command from
|
|
209
|
+
> a closure with `node:child_process`, and write what you need to the log.
|
|
210
|
+
|
|
211
|
+
## Running the scheduler
|
|
212
|
+
|
|
213
|
+
Add one cron entry to your server, which runs `schedule:run` every minute:
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
* * * * * cd /path-to-your-project && node oriel schedule:run >> /dev/null 2>&1
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`schedule:run` runs each due task once, prints its name, and goes on to the next one when a task fails, after
|
|
220
|
+
printing the error. With nothing due, it prints "No scheduled commands are ready to run.".
|
|
221
|
+
|
|
222
|
+
### Sub-minute tasks
|
|
223
|
+
|
|
224
|
+
A task that runs every few seconds, such as `everyTenSeconds()`, is due every minute. Its `schedule:run` runs it
|
|
225
|
+
again each time those seconds have passed, until the minute ends, then the next minute's `schedule:run` takes over:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
Schedule.call(async () => {
|
|
229
|
+
await DB.table('recent_users').delete()
|
|
230
|
+
}).everyTenSeconds()
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Since that `schedule:run` keeps going for the whole minute, a deploy would wait for it. `schedule:interrupt` tells it
|
|
234
|
+
to stop repeating its sub-minute tasks for the rest of the minute; run it as part of your deploy:
|
|
235
|
+
|
|
236
|
+
```sh
|
|
237
|
+
node oriel schedule:interrupt
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The signal is kept in your default cache store until the minute ends.
|
|
241
|
+
|
|
242
|
+
### Running the scheduler locally
|
|
243
|
+
|
|
244
|
+
On your own machine, run `schedule:work` instead of adding a cron entry. It runs the scheduler every minute in the
|
|
245
|
+
foreground, until you stop it:
|
|
246
|
+
|
|
247
|
+
```sh
|
|
248
|
+
node oriel schedule:work
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
When one minute's run fails, as when the cache can't be read, it reports the error and goes on with the next minute.
|
|
252
|
+
[Deployment](deployment.md#task-scheduling) shows both ways in production.
|
|
253
|
+
|
|
254
|
+
## Task hooks
|
|
255
|
+
|
|
256
|
+
`before()` runs a function before the task, and `after()` after it, whether it succeeded or not. `onSuccess()` runs
|
|
257
|
+
one when it succeeded, and `onFailure()` when it failed. Each may be async:
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
Schedule.command('emails:send')
|
|
261
|
+
.daily()
|
|
262
|
+
.before(() => {
|
|
263
|
+
// The task is about to run...
|
|
264
|
+
})
|
|
265
|
+
.after(() => {
|
|
266
|
+
// The task has run...
|
|
267
|
+
})
|
|
268
|
+
.onSuccess(() => {
|
|
269
|
+
// The task succeeded...
|
|
270
|
+
})
|
|
271
|
+
.onFailure(() => {
|
|
272
|
+
// The task failed...
|
|
273
|
+
})
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
`then()` is another name for `after()`. A task skipped by a constraint, an overlap or another server runs none of
|
|
277
|
+
its hooks.
|
package/docs/seeding.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Database: seeding
|
|
2
|
+
|
|
3
|
+
Seeders fill your database with data, such as a first user for your own machine or the rows your tests and demos
|
|
4
|
+
need.
|
|
5
|
+
|
|
6
|
+
## Introduction
|
|
7
|
+
|
|
8
|
+
A seeder is a class in `database/seeders` with a `run()` method. A new app has one, `DatabaseSeeder`, which `db:seed`
|
|
9
|
+
runs unless you name another. It creates a test user; add a `this.call()` for each seeder you write.
|
|
10
|
+
|
|
11
|
+
Seeders run with mass assignment protection off, so `create()` takes every attribute you give it.
|
|
12
|
+
|
|
13
|
+
## Writing seeders
|
|
14
|
+
|
|
15
|
+
`make:seeder` writes a seeder in `database/seeders`:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
node oriel make:seeder UserSeeder
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
A seeder's `run()` can insert rows with the [query builder](queries.md), or create models with their
|
|
22
|
+
[factories](#using-model-factories). It is async, so `await` each insert:
|
|
23
|
+
|
|
24
|
+
```ts title="database/seeders/UserSeeder.ts"
|
|
25
|
+
import { DB, Hash, Seeder, Str } from '@orieljs/framework'
|
|
26
|
+
|
|
27
|
+
export default class UserSeeder extends Seeder {
|
|
28
|
+
/** Run the database seeders. */
|
|
29
|
+
async run(): Promise<void> {
|
|
30
|
+
await DB.table('users').insert({
|
|
31
|
+
name: Str.random(10),
|
|
32
|
+
email: `${Str.random(10)}@example.com`,
|
|
33
|
+
password: await Hash.make('password'),
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The file's default export is the seeder, or its export named after the file.
|
|
40
|
+
|
|
41
|
+
### Using model factories
|
|
42
|
+
|
|
43
|
+
Factories make many rows at once, with realistic values. A new app's `DatabaseSeeder` uses the `User` factory:
|
|
44
|
+
|
|
45
|
+
```ts title="database/seeders/DatabaseSeeder.ts"
|
|
46
|
+
import { Seeder } from '@orieljs/framework'
|
|
47
|
+
import { User } from '../../app/Models/User'
|
|
48
|
+
|
|
49
|
+
export default class DatabaseSeeder extends Seeder {
|
|
50
|
+
async run(): Promise<void> {
|
|
51
|
+
await User.factory().create({
|
|
52
|
+
name: 'Test User',
|
|
53
|
+
email: 'test@example.com',
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`User.factory(50).create()` makes 50 users. [Factories](eloquent-factories.md) shows how to write factories and give
|
|
60
|
+
them related models.
|
|
61
|
+
|
|
62
|
+
### Calling additional seeders
|
|
63
|
+
|
|
64
|
+
`call()` runs other seeders, in order, and prints each one's name as it runs:
|
|
65
|
+
|
|
66
|
+
```ts title="database/seeders/DatabaseSeeder.ts"
|
|
67
|
+
// @filename: database/seeders/UserSeeder.ts
|
|
68
|
+
import { Seeder } from '@orieljs/framework'
|
|
69
|
+
export default class UserSeeder extends Seeder {
|
|
70
|
+
async run(): Promise<void> {}
|
|
71
|
+
}
|
|
72
|
+
// @filename: database/seeders/PostSeeder.ts
|
|
73
|
+
import { Seeder } from '@orieljs/framework'
|
|
74
|
+
export default class PostSeeder extends Seeder {
|
|
75
|
+
async run(): Promise<void> {}
|
|
76
|
+
}
|
|
77
|
+
// ---cut---
|
|
78
|
+
import { Seeder } from '@orieljs/framework'
|
|
79
|
+
import PostSeeder from './PostSeeder'
|
|
80
|
+
import UserSeeder from './UserSeeder'
|
|
81
|
+
|
|
82
|
+
export default class DatabaseSeeder extends Seeder {
|
|
83
|
+
async run(): Promise<void> {
|
|
84
|
+
await this.call(UserSeeder, PostSeeder)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`callSilent()` runs them without printing.
|
|
90
|
+
|
|
91
|
+
> [!NOTE]
|
|
92
|
+
> Laravel's `WithoutModelEvents` trait, which mutes model events while a seeder runs, and `callWith()` aren't in
|
|
93
|
+
> Oriel. Wrap the code in `Model.withoutEvents()` to mute the events.
|
|
94
|
+
|
|
95
|
+
## Running seeders
|
|
96
|
+
|
|
97
|
+
`db:seed` runs `DatabaseSeeder`. Name another seeder to run it alone:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
node oriel db:seed
|
|
101
|
+
|
|
102
|
+
node oriel db:seed UserSeeder
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`--database` runs the seeder on another connection, which becomes the default while it runs.
|
|
106
|
+
|
|
107
|
+
`--seed` runs `DatabaseSeeder` after `migrate`, `migrate:fresh` or `migrate:refresh`, and `--seeder` another one:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
node oriel migrate:fresh --seed
|
|
111
|
+
|
|
112
|
+
node oriel migrate:fresh --seed --seeder=UserSeeder
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### Forcing seeders to run in production
|
|
116
|
+
|
|
117
|
+
In production, `db:seed` stops unless you pass `--force`, so you can't fill your live database with test data by
|
|
118
|
+
mistake:
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
node oriel db:seed --force
|
|
122
|
+
```
|