Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/Melchyore/adonis-auto-preload
Auto-preload multiple relationships when retrieving Lucid models
https://github.com/Melchyore/adonis-auto-preload
Last synced: 3 months ago
JSON representation
Auto-preload multiple relationships when retrieving Lucid models
- Host: GitHub
- URL: https://github.com/Melchyore/adonis-auto-preload
- Owner: Melchyore
- License: mit
- Created: 2022-08-28T10:04:36.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2022-12-19T14:16:10.000Z (almost 2 years ago)
- Last Synced: 2024-07-10T19:57:27.479Z (4 months ago)
- Language: TypeScript
- Homepage:
- Size: 835 KB
- Stars: 30
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE.md
Awesome Lists containing this project
- awesome-adonisjs - Adonis Auto-Preload - Auto-preload multiple relationships when retrieving Lucid models (Packages)
README
## **Pre-requisites**
> Node.js >= 16.17.0## **Installation**
```sh
npm install @melchyore/adonis-auto-preload
# or
yarn add @melchyore/adonis-auto-preload
# or
pnpm install @melchyore/adonis-auto-preload
```
## **Configure**
```sh
node ace configure @melchyore/adonis-auto-preload
```## **Usage**
Extend from the AutoPreload mixin and add a new `static $with` attribute.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.
Relationships will be auto-preloaded for `find`, `all` and `paginate` queries.
### **Using relation name**
```ts
// App/Models/User.tsimport { BaseModel, column, hasMany, HasMany } from '@ioc:Adonis/Lucid/Orm'
import { compose } from '@ioc:Adonis/Core/Helpers'import { AutoPreload } from '@ioc:Adonis/Addons/AutoPreload'
import Post from 'App/Models/Post'
class User extends compose(BaseModel, AutoPreload) {
public static $with = ['posts'] as const@column({ isPrimary: true })
public id: number@column()
public email: string@hasMany(() => Post)
public posts: HasMany
}
``````ts
// App/Controllers/Http/UsersController.tsimport User from 'App/Models/User'
export default class UsersController {
public async show() {
return await User.find(1) // ⬅ Returns user with posts attached.
}
}
```### **Using function**
You can also use functions to auto-preload relationships. The function will receive the model query builder as the only argument.```ts
// App/Models/User.tsimport { BaseModel, column, hasMany, HasMany } from '@ioc:Adonis/Lucid/Orm'
import { compose } from '@ioc:Adonis/Core/Helpers'import { AutoPreload } from '@ioc:Adonis/Addons/AutoPreload'
import Post from 'App/Models/Post'
class User extends compose(BaseModel, AutoPreload) {
public static $with = [
(query: ModelQueryBuilderContract) => {
query.preload('posts')
}
]@column({ isPrimary: true })
public id: number@column()
public email: string@hasMany(() => Post)
public posts: HasMany
}
``````ts
// App/Controllers/Http/UsersController.tsimport User from 'App/Models/User'
export default class UsersController {
public async show() {
return await User.find(1) // ⬅ Returns user with posts attached.
}
}
```## **Nested relationships**
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`.```ts
// App/Models/Post.tsimport { BaseModel, column, hasMany, HasMany } from '@ioc:Adonis/Lucid/Orm'
import { compose } from '@ioc:Adonis/Core/Helpers'class Post extends BaseModel {
@column({ isPrimary: true })
public id: number@column()
public userId: number@column()
public title: string@column()
public content: string@hasMany(() => Comment)
public comments: HasMany
}
``````ts
// App/Models/User.tsimport { BaseModel, column, hasMany, HasMany } from '@ioc:Adonis/Lucid/Orm'
import { compose } from '@ioc:Adonis/Core/Helpers'import { AutoPreload } from '@ioc:Adonis/Addons/AutoPreload'
import Post from 'App/Models/Post'
class User extends compose(BaseModel, AutoPreload) {
public static $with = ['posts.comments'] as const@column({ isPrimary: true })
public id: number@column()
public email: string@hasMany(() => Post)
public posts: HasMany
}
```When retrieving a user, it will preload both `posts` and `comments` (`comments` will be attached to their `posts` parents objects).
You can also use functions to auto-preload nested relationships.
```ts
public static $with = [
(query: ModelQueryBuilderContract) => {
query.preload('posts', (postsQuery) => {
postsQuery.preload('comments')
})
}
]
```## **Mixin methods**
The `AutoPreload` mixin will add 3 methods to your models. We will explain all of them below.We will use the following model for our methods examples.
```ts
// App/Models/User.tsimport { BaseModel, column, hasOne, HasOne, hasMany, HasMany } from '@ioc:Adonis/Lucid/Orm'
import { compose } from '@ioc:Adonis/Core/Helpers'import { AutoPreload } from '@ioc:Adonis/Addons/AutoPreload'
import Profile from 'App/Models/Profile'
import Post from 'App/Models/Post'class User extends compose(BaseModel, AutoPreload) {
public static $with = ['posts', 'profile'] as const@column({ isPrimary: true })
public id: number@column()
public email: string@hasOne(() => Profile)
public profile: HasOne@hasMany(() => Post)
public posts: HasMany
}
```### **without**
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.```ts
// App/Controllers/Http/UsersController.tsimport User from 'App/Models/User'
export default class UsersController {
public async show() {
return await User.without(['posts']).find(1) // ⬅ Returns user with profile and without posts.
}
}
```### **withOnly**
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.```ts
// App/Controllers/Http/UsersController.tsimport User from 'App/Models/User'
export default class UsersController {
public async show() {
return await User.withOnly(['profile']).find(1) // ⬅ Returns user with profile and without posts.
}
}
```### **withoutAny**
Exclude all relationships from being auto-preloaded.```ts
// App/Controllers/Http/UsersController.tsimport User from 'App/Models/User'
export default class UsersController {
public async show() {
return await User.withoutAny().find(1) // ⬅ Returns user without profile and posts.
}
}
```> **Note**
>
> You can chain other model methods with mixin methods. For example, `await User.withoutAny().query().paginate(1)`## **Limitations**
- 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.## **Route model binding**
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.```ts
// App/Models/User.tsimport { BaseModel, column, hasOne, HasOne, hasMany, HasMany } from '@ioc:Adonis/Lucid/Orm'
import { compose } from '@ioc:Adonis/Core/Helpers'import { AutoPreload } from '@ioc:Adonis/Addons/AutoPreload'
import Profile from 'App/Models/Profile'
import Post from 'App/Models/Post'class User extends compose(BaseModel, AutoPreload) {
public static $with = ['posts', 'profile'] as const@column({ isPrimary: true })
public id: number@column()
public email: string@hasOne(() => Profile)
public profile: HasOne@hasMany(() => Post)
public posts: HasManypublic static findForRequest(ctx, param, value) {
const lookupKey = param.lookupKey === '$primaryKey' ? 'id' : param.lookupKeyreturn this
.without(['posts']) // ⬅ Do not auto-preload posts when using route model binding.
.query()
.where(lookupKey, value)
.firstOrFail()
}
}
```## **Run tests**
```sh
npm run test
```## **Author**
👤 **Oussama Benhamed**
* Twitter: [@Melchyore](https://twitter.com/Melchyore)
* Github: [@Melchyore](https://github.com/Melchyore)## 🤝 **Contributing**
Contributions, issues and feature requests are welcome!
Feel free to check [issues page](https://github.com/Melchyore/adonis-auto-preload/issues). You can also take a look at the [contributing guide](https://github.com/Melchyore/adonis-auto-preload/blob/master/CONTRIBUTING.md).## **Show your support**
Give a ⭐️ if this project helped you!
## 📝 **License**
Copyright © 2022 [Oussama Benhamed](https://github.com/Melchyore).
This project is [MIT](https://github.com/Melchyore/adonis-auto-preload/blob/master/LICENSE.md) licensed.