@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.
Files changed (3) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +315 -0
  3. 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
+ }