@codenameryuu/adonis-lucid-auto-preload 2.7.0 → 2.9.1
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The MIT License
|
|
2
2
|
|
|
3
|
-
Copyright
|
|
3
|
+
Copyright 2026 Codename Ryuu
|
|
4
4
|
|
|
5
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
6
|
|
package/README.md
CHANGED
|
@@ -40,6 +40,8 @@ Relationships will be auto-preloaded for `find` , `all` and `paginate` queries.
|
|
|
40
40
|
|
|
41
41
|
**Note:** Relationships must be `belongsTo` , if you are using other relationship types, it may cause infinite loop.
|
|
42
42
|
|
|
43
|
+
**Note:** Make sure `AutoPreload` extended in the last position, especially when using `SoftDeletes` package.
|
|
44
|
+
|
|
43
45
|
### **Using relation name**
|
|
44
46
|
|
|
45
47
|
```typescript
|
|
@@ -50,10 +52,11 @@ import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
|
|
50
52
|
import { compose } from "@adonisjs/core/helpers";
|
|
51
53
|
|
|
52
54
|
import { AutoPreload } from "@codenameryuu/adonis-lucid-auto-preload";
|
|
55
|
+
import { SoftDeletes } from "@codenameryuu/adonis-lucid-soft-deletes";
|
|
53
56
|
|
|
54
57
|
import ProductCategory from '#models/product-category'
|
|
55
58
|
|
|
56
|
-
class Product extends compose(BaseModel, AutoPreload) {
|
|
59
|
+
class Product extends compose(BaseModel, SoftDeletes, AutoPreload) {
|
|
57
60
|
public static $with = ['productCategory'] as const
|
|
58
61
|
|
|
59
62
|
@column({ isPrimary: true })
|
|
@@ -74,18 +77,6 @@ class Product extends compose(BaseModel, AutoPreload) {
|
|
|
74
77
|
}
|
|
75
78
|
```
|
|
76
79
|
|
|
77
|
-
### **Preload soft deleted belongsTo**
|
|
78
|
-
|
|
79
|
-
If you are using soft deletes (for example with [`@codenameryuu/adonis-lucid-soft-deletes`](https://github.com/codenameryuu/adonis-lucid-soft-deletes)), you may want a `belongsTo` relationship to be preloaded even when the related row is soft deleted.
|
|
80
|
-
|
|
81
|
-
You can opt-in per relationship using an object entry:
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
class Product extends compose(BaseModel, AutoPreload) {
|
|
85
|
-
public static $with = [{ relation: 'productCategory', withTrashed: true }] as const
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
80
|
```typescript
|
|
90
81
|
// App/Controllers/Http/ProductsController.ts
|
|
91
82
|
|
|
@@ -111,10 +102,11 @@ import type { ModelQueryBuilderContract } from '@adonisjs/lucid/types/model'
|
|
|
111
102
|
import { compose } from '@adonisjs/core/helpers'
|
|
112
103
|
|
|
113
104
|
import { AutoPreload } from '@codenameryuu/adonis-lucid-auto-preload'
|
|
105
|
+
import { SoftDeletes } from "@codenameryuu/adonis-lucid-soft-deletes";
|
|
114
106
|
|
|
115
107
|
import ProductCategory from '#models/product-category'
|
|
116
108
|
|
|
117
|
-
class Product extends compose(BaseModel, AutoPreload) {
|
|
109
|
+
class Product extends compose(BaseModel, SoftDeletes, AutoPreload) {
|
|
118
110
|
public static $with = [
|
|
119
111
|
(query: ModelQueryBuilderContract<typeof this>) => {
|
|
120
112
|
query.preload('productCategory')
|
|
@@ -163,10 +155,11 @@ import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
|
|
163
155
|
import { compose } from "@adonisjs/core/helpers";
|
|
164
156
|
|
|
165
157
|
import { AutoPreload } from "@codenameryuu/adonis-lucid-auto-preload";
|
|
158
|
+
import { SoftDeletes } from "@codenameryuu/adonis-lucid-soft-deletes";
|
|
166
159
|
|
|
167
160
|
import User from '#models/user'
|
|
168
161
|
|
|
169
|
-
class ProductCategory extends compose(BaseModel, AutoPreload) {
|
|
162
|
+
class ProductCategory extends compose(BaseModel, SoftDeletes, AutoPreload) {
|
|
170
163
|
public static $with = ['user'] as const
|
|
171
164
|
|
|
172
165
|
@column({ isPrimary: true })
|
|
@@ -195,10 +188,11 @@ import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
|
|
195
188
|
import { compose } from '@adonisjs/core/helpers'
|
|
196
189
|
|
|
197
190
|
import { AutoPreload } from '@codenameryuu/adonis-lucid-auto-preload'
|
|
191
|
+
import { SoftDeletes } from "@codenameryuu/adonis-lucid-soft-deletes";
|
|
198
192
|
|
|
199
193
|
import ProductCategory from '#models/product-category'
|
|
200
194
|
|
|
201
|
-
class Product extends compose(BaseModel, AutoPreload) {
|
|
195
|
+
class Product extends compose(BaseModel, SoftDeletes, AutoPreload) {
|
|
202
196
|
public static $with = ['productCategory.user'] as const
|
|
203
197
|
|
|
204
198
|
@column({ isPrimary: true })
|
|
@@ -3,13 +3,9 @@ import type { LucidModel } from '@adonisjs/lucid/types/model';
|
|
|
3
3
|
type GetWith<T> = T extends {
|
|
4
4
|
$with: Array<infer Item>;
|
|
5
5
|
} ? Item extends string ? Item : string : string;
|
|
6
|
-
type PreloadSpec = {
|
|
7
|
-
relation: string;
|
|
8
|
-
withTrashed?: boolean;
|
|
9
|
-
};
|
|
10
6
|
export interface AutoPreloadMixin {
|
|
11
7
|
<T extends NormalizeConstructor<LucidModel>>(superclass: T): T & {
|
|
12
|
-
$with: ReadonlyArray<string |
|
|
8
|
+
$with: ReadonlyArray<string | ((query: any) => void)>;
|
|
13
9
|
without(this: T, relationships: Array<GetWith<T>>): any;
|
|
14
10
|
withOnly(this: T, relationships: Array<GetWith<T>>): any;
|
|
15
11
|
withoutAny(this: T): any;
|
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
import type { NormalizeConstructor } from '@adonisjs/core/types/helpers';
|
|
2
2
|
import type { LucidModel, ModelQueryBuilderContract } from '@adonisjs/lucid/types/model';
|
|
3
|
-
type
|
|
4
|
-
relation: string;
|
|
5
|
-
/**
|
|
6
|
-
* When true, attempts to call `.withTrashed()` on the preload builder.
|
|
7
|
-
* Useful with `@codenameryuu/adonis-lucid-soft-deletes` when the related model
|
|
8
|
-
* may be soft deleted but should still be returned.
|
|
9
|
-
*/
|
|
10
|
-
withTrashed?: boolean;
|
|
11
|
-
};
|
|
12
|
-
type PreloadEntry = string | PreloadSpec | ((query: ModelQueryBuilderContract<any, any>) => void);
|
|
3
|
+
type PreloadEntry = string | ((query: ModelQueryBuilderContract<any, any>) => void);
|
|
13
4
|
export declare function AutoPreload<T extends NormalizeConstructor<LucidModel>>(superclass: T): {
|
|
14
5
|
new (...args: any[]): {
|
|
15
6
|
$attributes: import("@adonisjs/lucid/types/model").ModelObject;
|
|
@@ -70,12 +61,6 @@ export declare function AutoPreload<T extends NormalizeConstructor<LucidModel>>(
|
|
|
70
61
|
toAttributes(): Record<string, any>;
|
|
71
62
|
related<Name extends undefined>(relation: Name): NonNullable</*elided*/ any[Name]> extends import("@adonisjs/lucid/types/relations").ModelRelations<LucidModel, LucidModel> ? (import("@adonisjs/lucid/types/relations").ModelRelations<LucidModel, LucidModel> & /*elided*/ any[Name] & {})["client"] : never;
|
|
72
63
|
};
|
|
73
|
-
/**
|
|
74
|
-
* Propagate query flags used by other mixins (e.g. SoftDeletes) to preload builders.
|
|
75
|
-
* SoftDeletes uses `query.ignoreDeleted = false` for `.withTrashed()` / `.onlyTrashed()`.
|
|
76
|
-
*/
|
|
77
|
-
applyPreloadOptions(parent: any, child: any, options?: PreloadSpec): void;
|
|
78
|
-
inheritQueryFlags(parent: any, child: any): void;
|
|
79
64
|
/**
|
|
80
65
|
* List of relationships to auto-preload.
|
|
81
66
|
*/
|
|
@@ -85,7 +70,7 @@ export declare function AutoPreload<T extends NormalizeConstructor<LucidModel>>(
|
|
|
85
70
|
beforeFetchHook(query: ModelQueryBuilderContract<any, any>): void;
|
|
86
71
|
beforePaginateHook(queries: any): void;
|
|
87
72
|
applyAutoPreload(query: ModelQueryBuilderContract<any, any>): void;
|
|
88
|
-
handleNestedPreload(query: any, parts: string[]
|
|
73
|
+
handleNestedPreload(query: any, parts: string[]): void;
|
|
89
74
|
/**
|
|
90
75
|
* Correct Implementation: Returns the Query Builder to avoid global state pollution
|
|
91
76
|
*/
|
|
@@ -1,37 +1,5 @@
|
|
|
1
1
|
export function AutoPreload(superclass) {
|
|
2
2
|
class AutoPreloadModel extends superclass {
|
|
3
|
-
/**
|
|
4
|
-
* Propagate query flags used by other mixins (e.g. SoftDeletes) to preload builders.
|
|
5
|
-
* SoftDeletes uses `query.ignoreDeleted = false` for `.withTrashed()` / `.onlyTrashed()`.
|
|
6
|
-
*/
|
|
7
|
-
static applyPreloadOptions(parent, child, options) {
|
|
8
|
-
if (options?.withTrashed) {
|
|
9
|
-
if (typeof child?.withTrashed === 'function') {
|
|
10
|
-
child.withTrashed();
|
|
11
|
-
}
|
|
12
|
-
else {
|
|
13
|
-
/**
|
|
14
|
-
* Fallback for builders that don't have the `withTrashed` macro attached.
|
|
15
|
-
* `@codenameryuu/adonis-lucid-soft-deletes` checks `ignoreDeleted === false`.
|
|
16
|
-
*/
|
|
17
|
-
child.ignoreDeleted = false;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
this.inheritQueryFlags(parent, child);
|
|
21
|
-
}
|
|
22
|
-
static inheritQueryFlags(parent, child) {
|
|
23
|
-
if (!parent || !child)
|
|
24
|
-
return;
|
|
25
|
-
if (Object.prototype.hasOwnProperty.call(parent, 'ignoreDeleted') &&
|
|
26
|
-
parent.ignoreDeleted === false) {
|
|
27
|
-
if (typeof child.withTrashed === 'function') {
|
|
28
|
-
child.withTrashed();
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
child.ignoreDeleted = false;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
3
|
/**
|
|
36
4
|
* List of relationships to auto-preload.
|
|
37
5
|
*/
|
|
@@ -70,20 +38,16 @@ export function AutoPreload(superclass) {
|
|
|
70
38
|
const skipList = query.$skipPreloads || [];
|
|
71
39
|
const onlyList = query.$onlyPreloads || [];
|
|
72
40
|
for (const relation of relations) {
|
|
73
|
-
if (typeof relation === 'string'
|
|
74
|
-
|
|
75
|
-
const options = typeof relation === 'string' ? undefined : relation;
|
|
76
|
-
if (onlyList.length > 0 && !onlyList.includes(name))
|
|
41
|
+
if (typeof relation === 'string') {
|
|
42
|
+
if (onlyList.length > 0 && !onlyList.includes(relation))
|
|
77
43
|
continue;
|
|
78
|
-
if (skipList.includes(
|
|
44
|
+
if (skipList.includes(relation))
|
|
79
45
|
continue;
|
|
80
|
-
if (
|
|
81
|
-
this.handleNestedPreload(query,
|
|
46
|
+
if (relation.includes('.')) {
|
|
47
|
+
this.handleNestedPreload(query, relation.split('.'));
|
|
82
48
|
}
|
|
83
49
|
else {
|
|
84
|
-
query.preload(
|
|
85
|
-
this.applyPreloadOptions(query, builder, options);
|
|
86
|
-
});
|
|
50
|
+
query.preload(relation);
|
|
87
51
|
}
|
|
88
52
|
}
|
|
89
53
|
else if (typeof relation === 'function') {
|
|
@@ -91,15 +55,13 @@ export function AutoPreload(superclass) {
|
|
|
91
55
|
}
|
|
92
56
|
}
|
|
93
57
|
}
|
|
94
|
-
static handleNestedPreload(query, parts
|
|
58
|
+
static handleNestedPreload(query, parts) {
|
|
95
59
|
const current = parts.shift();
|
|
96
60
|
if (!current)
|
|
97
61
|
return;
|
|
98
62
|
query.preload(current, (builder) => {
|
|
99
|
-
// Apply options only to the first hop ("productCategory" in "productCategory.user")
|
|
100
|
-
this.applyPreloadOptions(query, builder, isRoot ? options : undefined);
|
|
101
63
|
if (parts.length > 0) {
|
|
102
|
-
this.handleNestedPreload(builder, [...parts]
|
|
64
|
+
this.handleNestedPreload(builder, [...parts]);
|
|
103
65
|
}
|
|
104
66
|
});
|
|
105
67
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codenameryuu/adonis-lucid-auto-preload",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.1",
|
|
4
4
|
"description": "Auto-preload (eager loading) multiple relationships when retrieving Lucid models on Adonis JS",
|
|
5
5
|
"author": "codenameryuu",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,9 +38,8 @@
|
|
|
38
38
|
"scripts": {
|
|
39
39
|
"clean": "del-cli build",
|
|
40
40
|
"typecheck": "tsc --noEmit",
|
|
41
|
-
"lint": "eslint . --ext=.ts",
|
|
42
41
|
"format": "prettier --write .",
|
|
43
|
-
"prebuild": "npm run
|
|
42
|
+
"prebuild": "npm run clean",
|
|
44
43
|
"build": "npm run clean && tsc",
|
|
45
44
|
"release": "release-it",
|
|
46
45
|
"version": "npm run build",
|
|
@@ -49,7 +48,6 @@
|
|
|
49
48
|
"devDependencies": {
|
|
50
49
|
"@adonisjs/assembler": "^7.7.0",
|
|
51
50
|
"@adonisjs/core": "^7.0.0",
|
|
52
|
-
"@adonisjs/eslint-config": "^3.0.0",
|
|
53
51
|
"@adonisjs/lucid": "^22.0.0",
|
|
54
52
|
"@adonisjs/prettier-config": "^1.4.5",
|
|
55
53
|
"@adonisjs/tsconfig": "^2.0.0",
|
|
@@ -65,7 +63,6 @@
|
|
|
65
63
|
"c8": "^9.1.0",
|
|
66
64
|
"copyfiles": "^2.4.1",
|
|
67
65
|
"del-cli": "^5.0.0",
|
|
68
|
-
"eslint": "^10.0.2",
|
|
69
66
|
"prettier": "^3.8.1",
|
|
70
67
|
"reflect-metadata": "^0.2.2",
|
|
71
68
|
"tsup": "^8.5.1",
|