@codenameryuu/adonis-lucid-auto-preload 2.5.0 → 2.6.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/README.md
CHANGED
|
@@ -74,6 +74,18 @@ class Product extends compose(BaseModel, AutoPreload) {
|
|
|
74
74
|
}
|
|
75
75
|
```
|
|
76
76
|
|
|
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
|
+
|
|
77
89
|
```typescript
|
|
78
90
|
// App/Controllers/Http/ProductsController.ts
|
|
79
91
|
|
|
@@ -3,9 +3,13 @@ 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
|
+
};
|
|
6
10
|
export interface AutoPreloadMixin {
|
|
7
11
|
<T extends NormalizeConstructor<LucidModel>>(superclass: T): T & {
|
|
8
|
-
$with: ReadonlyArray<string | ((query: any) => void)>;
|
|
12
|
+
$with: ReadonlyArray<string | PreloadSpec | ((query: any) => void)>;
|
|
9
13
|
without(this: T, relationships: Array<GetWith<T>>): any;
|
|
10
14
|
withOnly(this: T, relationships: Array<GetWith<T>>): any;
|
|
11
15
|
withoutAny(this: T): any;
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { NormalizeConstructor } from '@adonisjs/core/types/helpers';
|
|
2
2
|
import type { LucidModel, ModelQueryBuilderContract } from '@adonisjs/lucid/types/model';
|
|
3
|
-
type
|
|
3
|
+
type PreloadSpec = {
|
|
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);
|
|
4
13
|
export declare function AutoPreload<T extends NormalizeConstructor<LucidModel>>(superclass: T): {
|
|
5
14
|
new (...args: any[]): {
|
|
6
15
|
$attributes: import("@adonisjs/lucid/types/model").ModelObject;
|
|
@@ -65,6 +74,7 @@ export declare function AutoPreload<T extends NormalizeConstructor<LucidModel>>(
|
|
|
65
74
|
* Propagate query flags used by other mixins (e.g. SoftDeletes) to preload builders.
|
|
66
75
|
* SoftDeletes uses `query.ignoreDeleted = false` for `.withTrashed()` / `.onlyTrashed()`.
|
|
67
76
|
*/
|
|
77
|
+
applyPreloadOptions(parent: any, child: any, options?: PreloadSpec): void;
|
|
68
78
|
inheritQueryFlags(parent: any, child: any): void;
|
|
69
79
|
/**
|
|
70
80
|
* List of relationships to auto-preload.
|
|
@@ -75,7 +85,7 @@ export declare function AutoPreload<T extends NormalizeConstructor<LucidModel>>(
|
|
|
75
85
|
beforeFetchHook(query: ModelQueryBuilderContract<any, any>): void;
|
|
76
86
|
beforePaginateHook(queries: any): void;
|
|
77
87
|
applyAutoPreload(query: ModelQueryBuilderContract<any, any>): void;
|
|
78
|
-
handleNestedPreload(query: any, parts: string[]): void;
|
|
88
|
+
handleNestedPreload(query: any, parts: string[], options?: PreloadSpec, isRoot?: boolean): void;
|
|
79
89
|
/**
|
|
80
90
|
* Correct Implementation: Returns the Query Builder to avoid global state pollution
|
|
81
91
|
*/
|
|
@@ -4,6 +4,12 @@ export function AutoPreload(superclass) {
|
|
|
4
4
|
* Propagate query flags used by other mixins (e.g. SoftDeletes) to preload builders.
|
|
5
5
|
* SoftDeletes uses `query.ignoreDeleted = false` for `.withTrashed()` / `.onlyTrashed()`.
|
|
6
6
|
*/
|
|
7
|
+
static applyPreloadOptions(parent, child, options) {
|
|
8
|
+
if (options?.withTrashed && typeof child?.withTrashed === 'function') {
|
|
9
|
+
child.withTrashed();
|
|
10
|
+
}
|
|
11
|
+
this.inheritQueryFlags(parent, child);
|
|
12
|
+
}
|
|
7
13
|
static inheritQueryFlags(parent, child) {
|
|
8
14
|
if (!parent || !child)
|
|
9
15
|
return;
|
|
@@ -55,17 +61,19 @@ export function AutoPreload(superclass) {
|
|
|
55
61
|
const skipList = query.$skipPreloads || [];
|
|
56
62
|
const onlyList = query.$onlyPreloads || [];
|
|
57
63
|
for (const relation of relations) {
|
|
58
|
-
if (typeof relation === 'string') {
|
|
59
|
-
|
|
64
|
+
if (typeof relation === 'string' || (relation && typeof relation === 'object')) {
|
|
65
|
+
const name = typeof relation === 'string' ? relation : relation.relation;
|
|
66
|
+
const options = typeof relation === 'string' ? undefined : relation;
|
|
67
|
+
if (onlyList.length > 0 && !onlyList.includes(name))
|
|
60
68
|
continue;
|
|
61
|
-
if (skipList.includes(
|
|
69
|
+
if (skipList.includes(name))
|
|
62
70
|
continue;
|
|
63
|
-
if (
|
|
64
|
-
this.handleNestedPreload(query,
|
|
71
|
+
if (name.includes('.')) {
|
|
72
|
+
this.handleNestedPreload(query, name.split('.'), options, true);
|
|
65
73
|
}
|
|
66
74
|
else {
|
|
67
|
-
query.preload(
|
|
68
|
-
this.
|
|
75
|
+
query.preload(name, (builder) => {
|
|
76
|
+
this.applyPreloadOptions(query, builder, options);
|
|
69
77
|
});
|
|
70
78
|
}
|
|
71
79
|
}
|
|
@@ -74,14 +82,15 @@ export function AutoPreload(superclass) {
|
|
|
74
82
|
}
|
|
75
83
|
}
|
|
76
84
|
}
|
|
77
|
-
static handleNestedPreload(query, parts) {
|
|
85
|
+
static handleNestedPreload(query, parts, options, isRoot = false) {
|
|
78
86
|
const current = parts.shift();
|
|
79
87
|
if (!current)
|
|
80
88
|
return;
|
|
81
89
|
query.preload(current, (builder) => {
|
|
82
|
-
|
|
90
|
+
// Apply options only to the first hop ("productCategory" in "productCategory.user")
|
|
91
|
+
this.applyPreloadOptions(query, builder, isRoot ? options : undefined);
|
|
83
92
|
if (parts.length > 0) {
|
|
84
|
-
this.handleNestedPreload(builder, [...parts]);
|
|
93
|
+
this.handleNestedPreload(builder, [...parts], options, false);
|
|
85
94
|
}
|
|
86
95
|
});
|
|
87
96
|
}
|
package/package.json
CHANGED