@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 PreloadEntry = string | ((query: ModelQueryBuilderContract<any, any>) => void);
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
- if (onlyList.length > 0 && !onlyList.includes(relation))
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(relation))
69
+ if (skipList.includes(name))
62
70
  continue;
63
- if (relation.includes('.')) {
64
- this.handleNestedPreload(query, relation.split('.'));
71
+ if (name.includes('.')) {
72
+ this.handleNestedPreload(query, name.split('.'), options, true);
65
73
  }
66
74
  else {
67
- query.preload(relation, (builder) => {
68
- this.inheritQueryFlags(query, builder);
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
- this.inheritQueryFlags(query, builder);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codenameryuu/adonis-lucid-auto-preload",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "description": "Auto-preload (eager loading) multiple relationships when retrieving Lucid models on Adonis JS",
5
5
  "author": "codenameryuu",
6
6
  "license": "MIT",