@codenameryuu/adonis-lucid-auto-preload 1.0.0
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/LICENSE.md +9 -0
- package/README.md +315 -0
- package/package.json +85 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright 2022 Oussama Benhamed, contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# @codenameryuuu/adonis-lucid-auto-preload
|
|
2
|
+
|
|
3
|
+
Auto-preload multiple relationships when retrieving Lucid models on Adonis JS 7.
|
|
4
|
+
|
|
5
|
+
## Requirement
|
|
6
|
+
|
|
7
|
+
* Adonis Js 7
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
yarn add @codenameryuuu/adonis-lucid-auto-preload
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Configure
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
node ace configure @codenameryuuu/adonis-lucid-auto-preload
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
Extend from the AutoPreload mixin and add a new `static $with` attribute.
|
|
24
|
+
|
|
25
|
+
Adding `as const` to `$with` array will let the compiler know about your relationship names and infer them so you will have better intellisense when using `without` and `withOnly` methods.
|
|
26
|
+
|
|
27
|
+
Relationships will be auto-preloaded for `find` , `all` and `paginate` queries.
|
|
28
|
+
|
|
29
|
+
### **Using relation name**
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// App/Models/User.ts
|
|
33
|
+
|
|
34
|
+
import { BaseModel, column, hasMany, HasMany } from '@adonisjs/lucid/orm'
|
|
35
|
+
import { compose } from '@adonisjs/core/helpers'
|
|
36
|
+
|
|
37
|
+
import { AutoPreload } from '@codenameryuuu/adonis-lucid-auto-preload'
|
|
38
|
+
|
|
39
|
+
import Post from '#models/post'
|
|
40
|
+
|
|
41
|
+
class User extends compose(BaseModel, AutoPreload) {
|
|
42
|
+
public static $with = ['posts'] as const
|
|
43
|
+
|
|
44
|
+
@column({ isPrimary: true })
|
|
45
|
+
public id: number
|
|
46
|
+
|
|
47
|
+
@column()
|
|
48
|
+
public email: string
|
|
49
|
+
|
|
50
|
+
@hasMany(() => Post)
|
|
51
|
+
public posts: HasMany<typeof Post>
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// App/Controllers/Http/UsersController.ts
|
|
57
|
+
|
|
58
|
+
import User from '#models/user'
|
|
59
|
+
|
|
60
|
+
export default class UsersController {
|
|
61
|
+
public async show() {
|
|
62
|
+
return await User.find(1) // ⬅ Returns user with posts attached.
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### **Using function**
|
|
68
|
+
|
|
69
|
+
You can also use functions to auto-preload relationships. The function will receive the model query builder as the only argument.
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// App/Models/User.ts
|
|
73
|
+
|
|
74
|
+
import { BaseModel, column, hasMany, HasMany } from '@adonisjs/lucid/orm'
|
|
75
|
+
import type { ModelQueryBuilderContract } from '@adonisjs/lucid/types/model'
|
|
76
|
+
import { compose } from '@adonisjs/core/helpers'
|
|
77
|
+
|
|
78
|
+
import { AutoPreload } from '@codenameryuuu/adonis-lucid-auto-preload'
|
|
79
|
+
|
|
80
|
+
import Post from '#models/post'
|
|
81
|
+
|
|
82
|
+
class User extends compose(BaseModel, AutoPreload) {
|
|
83
|
+
public static $with = [
|
|
84
|
+
(query: ModelQueryBuilderContract<typeof this>) => {
|
|
85
|
+
query.preload('posts')
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
@column({ isPrimary: true })
|
|
90
|
+
public id: number
|
|
91
|
+
|
|
92
|
+
@column()
|
|
93
|
+
public email: string
|
|
94
|
+
|
|
95
|
+
@hasMany(() => Post)
|
|
96
|
+
public posts: HasMany<typeof Post>
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// App/Controllers/Http/UsersController.ts
|
|
102
|
+
|
|
103
|
+
import User from '#models/user'
|
|
104
|
+
|
|
105
|
+
export default class UsersController {
|
|
106
|
+
public async show() {
|
|
107
|
+
return await User.find(1) // ⬅ Returns user with posts attached.
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Nested relationships
|
|
113
|
+
|
|
114
|
+
You can auto-preload nested relationships using the dot "." between the parent model and the child model. In the following example, `User` -> hasMany -> `Post` -> hasMany -> `Comment` .
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// App/Models/Post.ts
|
|
118
|
+
|
|
119
|
+
import { BaseModel, column, hasMany, HasMany } from '@adonisjs/lucid/orm'
|
|
120
|
+
|
|
121
|
+
class Post extends BaseModel {
|
|
122
|
+
@column({ isPrimary: true })
|
|
123
|
+
public id: number
|
|
124
|
+
|
|
125
|
+
@column()
|
|
126
|
+
public userId: number
|
|
127
|
+
|
|
128
|
+
@column()
|
|
129
|
+
public title: string
|
|
130
|
+
|
|
131
|
+
@column()
|
|
132
|
+
public content: string
|
|
133
|
+
|
|
134
|
+
@hasMany(() => Comment)
|
|
135
|
+
public comments: HasMany<typeof Comment>
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// App/Models/User.ts
|
|
141
|
+
|
|
142
|
+
import { BaseModel, column, hasMany, HasMany } from '@adonisjs/lucid/orm'
|
|
143
|
+
import { compose } from '@adonisjs/core/helpers'
|
|
144
|
+
|
|
145
|
+
import { AutoPreload } from '@codenameryuuu/adonis-lucid-auto-preload'
|
|
146
|
+
|
|
147
|
+
import Post from '#models/post'
|
|
148
|
+
|
|
149
|
+
class User extends compose(BaseModel, AutoPreload) {
|
|
150
|
+
public static $with = ['posts.comments'] as const
|
|
151
|
+
|
|
152
|
+
@column({ isPrimary: true })
|
|
153
|
+
public id: number
|
|
154
|
+
|
|
155
|
+
@column()
|
|
156
|
+
public email: string
|
|
157
|
+
|
|
158
|
+
@hasMany(() => Post)
|
|
159
|
+
public posts: HasMany<typeof Post>
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
When retrieving a user, it will preload both `posts` and `comments` ( `comments` will be attached to their `posts` parents objects).
|
|
164
|
+
|
|
165
|
+
You can also use functions to auto-preload nested relationships.
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
public static $with = [
|
|
169
|
+
(query: ModelQueryBuilderContract<typeof this>) => {
|
|
170
|
+
query.preload('posts', (postsQuery) => {
|
|
171
|
+
postsQuery.preload('comments')
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## **Mixin methods**
|
|
178
|
+
|
|
179
|
+
The `AutoPreload` mixin will add 3 methods to your models. We will explain all of them below.
|
|
180
|
+
|
|
181
|
+
We will use the following model for our methods examples.
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// App/Models/User.ts
|
|
185
|
+
|
|
186
|
+
import { BaseModel, column, hasOne, HasOne, hasMany, HasMany } from '@adonisjs/lucid/orm'
|
|
187
|
+
import { compose } from '@adonisjs/core/helpers'
|
|
188
|
+
|
|
189
|
+
import { AutoPreload } from '@codenameryuuu/adonis-lucid-auto-preload'
|
|
190
|
+
|
|
191
|
+
import Profile from '#models/profile'
|
|
192
|
+
import Post from '#models/post'
|
|
193
|
+
|
|
194
|
+
class User extends compose(BaseModel, AutoPreload) {
|
|
195
|
+
public static $with = ['posts', 'profile'] as const
|
|
196
|
+
|
|
197
|
+
@column({ isPrimary: true })
|
|
198
|
+
public id: number
|
|
199
|
+
|
|
200
|
+
@column()
|
|
201
|
+
public email: string
|
|
202
|
+
|
|
203
|
+
@hasOne(() => Profile)
|
|
204
|
+
public profile: HasOne<typeof Profile>
|
|
205
|
+
|
|
206
|
+
@hasMany(() => Post)
|
|
207
|
+
public posts: HasMany<typeof Post>
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### **without**
|
|
212
|
+
|
|
213
|
+
This method takes an array of relationship names as the only argument. All specified relationships will not be auto-preloaded. You cannot specify relationships registered using functions.
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// App/Controllers/Http/UsersController.ts
|
|
217
|
+
|
|
218
|
+
import User from '#models/user'
|
|
219
|
+
|
|
220
|
+
export default class UsersController {
|
|
221
|
+
public async show() {
|
|
222
|
+
return await User.without(['posts']).find(1) // ⬅ Returns user with profile and without posts.
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### **withOnly**
|
|
228
|
+
|
|
229
|
+
This method takes an array of relationship names as the only argument. Only specified relationships will be auto-preloaded. You cannot specify relationships registered using functions.
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// App/Controllers/Http/UsersController.ts
|
|
233
|
+
|
|
234
|
+
import User from '#models/user'
|
|
235
|
+
|
|
236
|
+
export default class UsersController {
|
|
237
|
+
public async show() {
|
|
238
|
+
return await User.withOnly(['profile']).find(1) // ⬅ Returns user with profile and without posts.
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### **withoutAny**
|
|
244
|
+
|
|
245
|
+
Exclude all relationships from being auto-preloaded.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// App/Controllers/Http/UsersController.ts
|
|
249
|
+
|
|
250
|
+
import User from '#models/user'
|
|
251
|
+
|
|
252
|
+
export default class UsersController {
|
|
253
|
+
public async show() {
|
|
254
|
+
return await User.withoutAny().find(1) // ⬅ Returns user without profile and posts.
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
> **Note**
|
|
260
|
+
>
|
|
261
|
+
> You can chain other model methods with mixin methods. For example, `await User.withoutAny().query().paginate(1)`
|
|
262
|
+
|
|
263
|
+
## **Limitations**
|
|
264
|
+
|
|
265
|
+
* Consider the following scenario: `User` -> hasMany -> `Post` -> hasMany -> `Comments`. If you auto-preload `user` and `comments` from `Post` and you auto-preload `posts` from `User`, you will end-up in a infinite loop and your application will stop working.
|
|
266
|
+
|
|
267
|
+
## **Route model binding**
|
|
268
|
+
|
|
269
|
+
When using route model binding, you cannot use `without` , `withOnly` and `withoutAny` methods in your controller. But, you can make use of [findForRequest](https://github.com/adonisjs/route-model-binding#change-lookup-logic) method.
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
// App/Models/User.ts
|
|
273
|
+
|
|
274
|
+
import { BaseModel, column, hasOne, HasOne, hasMany, HasMany } from '@adonisjs/lucid/orm'
|
|
275
|
+
import { compose } from '@adonisjs/core/helpers'
|
|
276
|
+
|
|
277
|
+
import { AutoPreload } from '@codenameryuuu/adonis-lucid-auto-preload'
|
|
278
|
+
|
|
279
|
+
import Profile from '#models/profile'
|
|
280
|
+
import Post from '#models/post'
|
|
281
|
+
|
|
282
|
+
class User extends compose(BaseModel, AutoPreload) {
|
|
283
|
+
public static $with = ['posts', 'profile'] as const
|
|
284
|
+
|
|
285
|
+
@column({ isPrimary: true })
|
|
286
|
+
public id: number
|
|
287
|
+
|
|
288
|
+
@column()
|
|
289
|
+
public email: string
|
|
290
|
+
|
|
291
|
+
@hasOne(() => Profile)
|
|
292
|
+
public profile: HasOne<typeof Profile>
|
|
293
|
+
|
|
294
|
+
@hasMany(() => Post)
|
|
295
|
+
public posts: HasMany<typeof Post>
|
|
296
|
+
|
|
297
|
+
public static findForRequest(ctx, param, value) {
|
|
298
|
+
const lookupKey = param.lookupKey === '$primaryKey' ? 'id' : param.lookupKey
|
|
299
|
+
|
|
300
|
+
return this
|
|
301
|
+
.without(['posts']) // ⬅ Do not auto-preload posts when using route model binding.
|
|
302
|
+
.query()
|
|
303
|
+
.where(lookupKey, value)
|
|
304
|
+
.firstOrFail()
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Contributing
|
|
310
|
+
|
|
311
|
+
Contributions, issues and feature requests are welcome!<br />Feel free to check [issues page](https://github.com/codenameryuuu/adonis-lucid-auto-preload/issues). You can also take a look at the [contributing guide](https://github.com/codenameryuuu/adonis-lucid-auto-preload/blob/master/CONTRIBUTING.md).
|
|
312
|
+
|
|
313
|
+
## License
|
|
314
|
+
|
|
315
|
+
This project is [MIT](https://github.com/codenameryuuu/adonis-lucid-auto-preload/blob/master/LICENSE.md) licensed.
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codenameryuu/adonis-lucid-auto-preload",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Auto-preload multiple relationships when retrieving Lucid models on Adonis JS 7",
|
|
5
|
+
"author": "codenameryuu",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/codenameryuu/adonis-lucid-auto-preload#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/codenameryuu/adonis-lucid-auto-preload.git"
|
|
11
|
+
},
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=24.0.0"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"adonis",
|
|
17
|
+
"adonisjs",
|
|
18
|
+
"auto-preload"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"dev": "node ace serve --watch",
|
|
22
|
+
"build": "npm run clean && tsc",
|
|
23
|
+
"start": "node server.js",
|
|
24
|
+
"lint": "eslint . --ext=.ts",
|
|
25
|
+
"format": "prettier --write .",
|
|
26
|
+
"pretest": "npm run lint",
|
|
27
|
+
"test": "node -r @adonisjs/require-ts/build/register bin",
|
|
28
|
+
"clean": "del-cli build",
|
|
29
|
+
"copyfiles": "copyfiles \"templates/**/*.txt\" \"instructions.md\" build",
|
|
30
|
+
"compile": "npm run lint && npm run clean && tsc && npm run copyfiles",
|
|
31
|
+
"commit": "git-cz",
|
|
32
|
+
"release": "np --message=\"chore(release): %s\""
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@adonisjs/assembler": "^7.7.0",
|
|
36
|
+
"@adonisjs/core": "^7.0.0",
|
|
37
|
+
"@adonisjs/eslint-config": "^3.0.0",
|
|
38
|
+
"@adonisjs/lucid": "^22.0.0",
|
|
39
|
+
"@adonisjs/prettier-config": "^1.4.5",
|
|
40
|
+
"@adonisjs/tsconfig": "^2.0.0",
|
|
41
|
+
"@japa/assert": "^4.2.0",
|
|
42
|
+
"@japa/expect": "^3.0.7",
|
|
43
|
+
"@japa/expect-type": "^2.0.4",
|
|
44
|
+
"@japa/file-system": "^3.0.0",
|
|
45
|
+
"@japa/run-failed-tests": "^1.1.1",
|
|
46
|
+
"@japa/runner": "^5.3.0",
|
|
47
|
+
"@japa/snapshot": "^2.0.5",
|
|
48
|
+
"@japa/spec-reporter": "^1.3.3",
|
|
49
|
+
"@poppinss/dev-utils": "^2.0.3",
|
|
50
|
+
"@types/node": "^25.5.0",
|
|
51
|
+
"copyfiles": "^2.4.1",
|
|
52
|
+
"del-cli": "^5.0.0",
|
|
53
|
+
"eslint": "^10.0.2",
|
|
54
|
+
"prettier": "^3.8.1",
|
|
55
|
+
"sqlite3": "^5.0.11",
|
|
56
|
+
"typescript": "^5.3.3",
|
|
57
|
+
"youch": "^4.1.0"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"reflect-metadata": "^0.2.2"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"@adonisjs/core": "^7.0.0",
|
|
64
|
+
"@adonisjs/lucid": "^22.0.0"
|
|
65
|
+
},
|
|
66
|
+
"eslintConfig": {
|
|
67
|
+
"extends": "@adonisjs/eslint-config/package"
|
|
68
|
+
},
|
|
69
|
+
"eslintIgnore": [
|
|
70
|
+
"build"
|
|
71
|
+
],
|
|
72
|
+
"prettier": "@adonisjs/prettier-config",
|
|
73
|
+
"publishConfig": {
|
|
74
|
+
"tag": "latest",
|
|
75
|
+
"access": "public"
|
|
76
|
+
},
|
|
77
|
+
"main": "./build/providers/AutoPreloadProvider.js",
|
|
78
|
+
"types": "./build/adonis-typings/index.d.ts",
|
|
79
|
+
"files": [
|
|
80
|
+
"build/adonis-typings",
|
|
81
|
+
"build/providers",
|
|
82
|
+
"build/src",
|
|
83
|
+
"build/instructions.md"
|
|
84
|
+
]
|
|
85
|
+
}
|