@holoyan/adonisjs-polymorphic 0.1.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 +549 -0
- package/build/configure.d.ts +10 -0
- package/build/configure.d.ts.map +1 -0
- package/build/configure.js +27 -0
- package/build/configure.js.map +1 -0
- package/build/providers/plugin_provider.d.ts +15 -0
- package/build/providers/plugin_provider.d.ts.map +1 -0
- package/build/providers/plugin_provider.js +21 -0
- package/build/providers/plugin_provider.js.map +1 -0
- package/build/src/decorators.d.ts +41 -0
- package/build/src/decorators.d.ts.map +1 -0
- package/build/src/decorators.js +64 -0
- package/build/src/decorators.js.map +1 -0
- package/build/src/define_config.d.ts +20 -0
- package/build/src/define_config.d.ts.map +1 -0
- package/build/src/define_config.js +8 -0
- package/build/src/define_config.js.map +1 -0
- package/build/src/index.d.ts +16 -0
- package/build/src/index.d.ts.map +1 -0
- package/build/src/index.js +15 -0
- package/build/src/index.js.map +1 -0
- package/build/src/relations/morph_many/index.d.ts +39 -0
- package/build/src/relations/morph_many/index.d.ts.map +1 -0
- package/build/src/relations/morph_many/index.js +110 -0
- package/build/src/relations/morph_many/index.js.map +1 -0
- package/build/src/relations/morph_many/query_builder.d.ts +22 -0
- package/build/src/relations/morph_many/query_builder.d.ts.map +1 -0
- package/build/src/relations/morph_many/query_builder.js +80 -0
- package/build/src/relations/morph_many/query_builder.js.map +1 -0
- package/build/src/relations/morph_many/query_client.d.ts +40 -0
- package/build/src/relations/morph_many/query_client.d.ts.map +1 -0
- package/build/src/relations/morph_many/query_client.js +115 -0
- package/build/src/relations/morph_many/query_client.js.map +1 -0
- package/build/src/relations/morph_one/index.d.ts +68 -0
- package/build/src/relations/morph_one/index.d.ts.map +1 -0
- package/build/src/relations/morph_one/index.js +147 -0
- package/build/src/relations/morph_one/index.js.map +1 -0
- package/build/src/relations/morph_one/query_builder.d.ts +22 -0
- package/build/src/relations/morph_one/query_builder.d.ts.map +1 -0
- package/build/src/relations/morph_one/query_builder.js +79 -0
- package/build/src/relations/morph_one/query_builder.js.map +1 -0
- package/build/src/relations/morph_one/query_client.d.ts +41 -0
- package/build/src/relations/morph_one/query_client.d.ts.map +1 -0
- package/build/src/relations/morph_one/query_client.js +94 -0
- package/build/src/relations/morph_one/query_client.js.map +1 -0
- package/build/src/relations/morph_to/eager_loader.d.ts +29 -0
- package/build/src/relations/morph_to/eager_loader.d.ts.map +1 -0
- package/build/src/relations/morph_to/eager_loader.js +78 -0
- package/build/src/relations/morph_to/eager_loader.js.map +1 -0
- package/build/src/relations/morph_to/index.d.ts +76 -0
- package/build/src/relations/morph_to/index.d.ts.map +1 -0
- package/build/src/relations/morph_to/index.js +172 -0
- package/build/src/relations/morph_to/index.js.map +1 -0
- package/build/src/relations/morph_to/query_client.d.ts +27 -0
- package/build/src/relations/morph_to/query_client.d.ts.map +1 -0
- package/build/src/relations/morph_to/query_client.js +64 -0
- package/build/src/relations/morph_to/query_client.js.map +1 -0
- package/build/src/relations/morph_to/registry.d.ts +2 -0
- package/build/src/relations/morph_to/registry.d.ts.map +1 -0
- package/build/src/relations/morph_to/registry.js +13 -0
- package/build/src/relations/morph_to/registry.js.map +1 -0
- package/build/src/relations/shared/query_builder.d.ts +55 -0
- package/build/src/relations/shared/query_builder.d.ts.map +1 -0
- package/build/src/relations/shared/query_builder.js +70 -0
- package/build/src/relations/shared/query_builder.js.map +1 -0
- package/build/src/types.d.ts +84 -0
- package/build/src/types.d.ts.map +1 -0
- package/build/src/types.js +2 -0
- package/build/src/types.js.map +1 -0
- package/build/stubs/config/polymorphic.stub +19 -0
- package/build/stubs/main.d.ts +6 -0
- package/build/stubs/main.d.ts.map +1 -0
- package/build/stubs/main.js +6 -0
- package/build/stubs/main.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { MorphToOptions } from '../../types.js';
|
|
2
|
+
import { MorphToEagerLoader } from './eager_loader.js';
|
|
3
|
+
import { MorphToQueryClient } from './query_client.js';
|
|
4
|
+
/**
|
|
5
|
+
* MorphTo relation - the child model belongs to one of many possible parent types.
|
|
6
|
+
*
|
|
7
|
+
* Example: Comment morphTo Post | Video (commentable)
|
|
8
|
+
* comments table has: commentable_type = 'posts'|'videos', commentable_id = parent.id
|
|
9
|
+
*/
|
|
10
|
+
export declare class MorphTo {
|
|
11
|
+
readonly relationName: string;
|
|
12
|
+
private readonly options;
|
|
13
|
+
readonly model: any;
|
|
14
|
+
/**
|
|
15
|
+
* Use 'belongsTo' so the Lucid preloader handles single-parent eager loading
|
|
16
|
+
* correctly (passes result[0] instead of full array).
|
|
17
|
+
*/
|
|
18
|
+
readonly type = "belongsTo";
|
|
19
|
+
booted: boolean;
|
|
20
|
+
serializeAs: string | null;
|
|
21
|
+
onQueryHook: ((query: any) => void) | undefined;
|
|
22
|
+
/** Explicit morph map (optional when global registry is used) */
|
|
23
|
+
morphMap: Record<string, () => any> | undefined;
|
|
24
|
+
/** Attribute name for the type column on THIS (child) model */
|
|
25
|
+
morphTypeKey: string;
|
|
26
|
+
/** DB column name for the type column */
|
|
27
|
+
morphTypeColumnName: string;
|
|
28
|
+
/** Attribute name for the id column on THIS (child) model */
|
|
29
|
+
morphIdKey: string;
|
|
30
|
+
/** DB column name for the id column */
|
|
31
|
+
morphIdColumnName: string;
|
|
32
|
+
/** Reverse map: model table name -> morph type string (built at boot) */
|
|
33
|
+
private reverseMorphMap;
|
|
34
|
+
constructor(relationName: string, options: MorphToOptions, model: any);
|
|
35
|
+
/**
|
|
36
|
+
* morphTo doesn't have a single relatedModel() since the type is dynamic.
|
|
37
|
+
* This is a placeholder used for compatibility with some Lucid internals.
|
|
38
|
+
*/
|
|
39
|
+
relatedModel(): never;
|
|
40
|
+
clone(parent: any): MorphTo;
|
|
41
|
+
boot(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Resolves the model factory for a given morph type string.
|
|
44
|
+
* Checks the explicit morphMap first, then falls back to the global registry.
|
|
45
|
+
*/
|
|
46
|
+
resolveModelFactory(morphType: string): (() => any) | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Looks up the morph type string for a given model class.
|
|
49
|
+
* Checks the explicit reverse map first, then falls back to the global registry.
|
|
50
|
+
* Used by MorphToQueryClient.associate().
|
|
51
|
+
*/
|
|
52
|
+
getMorphTypeFor(ModelClass: any): string | undefined;
|
|
53
|
+
setRelated(parent: any, related: any): void;
|
|
54
|
+
pushRelated(parent: any, related: any): void;
|
|
55
|
+
/**
|
|
56
|
+
* Matches and sets related models on each parent during eager loading.
|
|
57
|
+
* Uses __morphType and __morphPk stored in $extras by MorphToEagerLoader.exec().
|
|
58
|
+
*/
|
|
59
|
+
setRelatedForMany(parents: any[], related: any[]): void;
|
|
60
|
+
client(parent: any, client: any): MorphToQueryClient;
|
|
61
|
+
/**
|
|
62
|
+
* Returns the eager loader (used by the Lucid preloader).
|
|
63
|
+
* For a single parent, wrap it in an array for unified handling.
|
|
64
|
+
*/
|
|
65
|
+
eagerQuery(parent: any | any[], client: any): MorphToEagerLoader;
|
|
66
|
+
/**
|
|
67
|
+
* MorphTo subqueries are not supported.
|
|
68
|
+
*/
|
|
69
|
+
subQuery(_client: any): never;
|
|
70
|
+
/**
|
|
71
|
+
* MorphTo does not hydrate for persistence (the child model owns the FK columns
|
|
72
|
+
* and they are set via associate() or directly by the user).
|
|
73
|
+
*/
|
|
74
|
+
hydrateForPersistance(_parent: any, _related: any): void;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/relations/morph_to/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAGtD;;;;;GAKG;AACH,qBAAa,OAAO;aA2BA,YAAY,EAAE,MAAM;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO;aACR,KAAK,EAAE,GAAG;IA5B5B;;;OAGG;IACH,QAAQ,CAAC,IAAI,eAAc;IAC3B,MAAM,UAAQ;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAE1B,WAAW,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;IAE/C,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAA;IAE/C,+DAA+D;IAC/D,YAAY,EAAG,MAAM,CAAA;IACrB,yCAAyC;IACzC,mBAAmB,EAAG,MAAM,CAAA;IAC5B,6DAA6D;IAC7D,UAAU,EAAG,MAAM,CAAA;IACnB,uCAAuC;IACvC,iBAAiB,EAAG,MAAM,CAAA;IAE1B,yEAAyE;IACzE,OAAO,CAAC,eAAe,CAA8B;gBAGnC,YAAY,EAAE,MAAM,EACnB,OAAO,EAAE,cAAc,EACxB,KAAK,EAAE,GAAG;IAQ5B;;;OAGG;IACH,YAAY,IAAI,KAAK;IAOrB,KAAK,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO;IAI3B,IAAI,IAAI,IAAI;IAuCZ;;;OAGG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,SAAS;IAW/D;;;;OAIG;IACH,eAAe,CAAC,UAAU,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS;IAUpD,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,GAAG,IAAI;IAK3C,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,GAAG,IAAI;IAK5C;;;OAGG;IACH,iBAAiB,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI;IAsBvD,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,kBAAkB;IAKpD;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,EAAE,MAAM,EAAE,GAAG,GAAG,kBAAkB;IAMhE;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,KAAK;IAM7B;;;OAGG;IACH,qBAAqB,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,GAAG,IAAI;CAGzD"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { MorphToEagerLoader } from './eager_loader.js';
|
|
2
|
+
import { MorphToQueryClient } from './query_client.js';
|
|
3
|
+
import { getRegistry } from './registry.js';
|
|
4
|
+
/**
|
|
5
|
+
* MorphTo relation - the child model belongs to one of many possible parent types.
|
|
6
|
+
*
|
|
7
|
+
* Example: Comment morphTo Post | Video (commentable)
|
|
8
|
+
* comments table has: commentable_type = 'posts'|'videos', commentable_id = parent.id
|
|
9
|
+
*/
|
|
10
|
+
export class MorphTo {
|
|
11
|
+
relationName;
|
|
12
|
+
options;
|
|
13
|
+
model;
|
|
14
|
+
/**
|
|
15
|
+
* Use 'belongsTo' so the Lucid preloader handles single-parent eager loading
|
|
16
|
+
* correctly (passes result[0] instead of full array).
|
|
17
|
+
*/
|
|
18
|
+
type = 'belongsTo';
|
|
19
|
+
booted = false;
|
|
20
|
+
serializeAs;
|
|
21
|
+
onQueryHook;
|
|
22
|
+
/** Explicit morph map (optional when global registry is used) */
|
|
23
|
+
morphMap;
|
|
24
|
+
/** Attribute name for the type column on THIS (child) model */
|
|
25
|
+
morphTypeKey;
|
|
26
|
+
/** DB column name for the type column */
|
|
27
|
+
morphTypeColumnName;
|
|
28
|
+
/** Attribute name for the id column on THIS (child) model */
|
|
29
|
+
morphIdKey;
|
|
30
|
+
/** DB column name for the id column */
|
|
31
|
+
morphIdColumnName;
|
|
32
|
+
/** Reverse map: model table name -> morph type string (built at boot) */
|
|
33
|
+
reverseMorphMap = new Map();
|
|
34
|
+
constructor(relationName, options, model) {
|
|
35
|
+
this.relationName = relationName;
|
|
36
|
+
this.options = options;
|
|
37
|
+
this.model = model;
|
|
38
|
+
this.onQueryHook = options.onQuery;
|
|
39
|
+
this.morphMap = options.morphMap;
|
|
40
|
+
this.serializeAs =
|
|
41
|
+
options.serializeAs === undefined ? relationName : options.serializeAs;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* morphTo doesn't have a single relatedModel() since the type is dynamic.
|
|
45
|
+
* This is a placeholder used for compatibility with some Lucid internals.
|
|
46
|
+
*/
|
|
47
|
+
relatedModel() {
|
|
48
|
+
throw new Error(`[MorphTo] relatedModel() cannot be called on a morphTo relation. ` +
|
|
49
|
+
`The related model is determined at runtime from the morph type value.`);
|
|
50
|
+
}
|
|
51
|
+
clone(parent) {
|
|
52
|
+
return new MorphTo(this.relationName, { ...this.options }, parent);
|
|
53
|
+
}
|
|
54
|
+
boot() {
|
|
55
|
+
if (this.booted)
|
|
56
|
+
return;
|
|
57
|
+
// Derive attribute names from name option or explicit typeKey/idKey
|
|
58
|
+
const name = this.options.name ?? this.relationName;
|
|
59
|
+
const typeAttr = this.options.typeKey ?? `${name}Type`;
|
|
60
|
+
const idAttr = this.options.idKey ?? `${name}Id`;
|
|
61
|
+
const typeColDef = this.model.$getColumn(typeAttr);
|
|
62
|
+
if (!typeColDef) {
|
|
63
|
+
throw new Error(`[MorphTo] "${typeAttr}" column not found on "${this.model.name}". ` +
|
|
64
|
+
`Add @column() declare ${typeAttr}: string`);
|
|
65
|
+
}
|
|
66
|
+
const idColDef = this.model.$getColumn(idAttr);
|
|
67
|
+
if (!idColDef) {
|
|
68
|
+
throw new Error(`[MorphTo] "${idAttr}" column not found on "${this.model.name}". ` +
|
|
69
|
+
`Add @column() declare ${idAttr}: number`);
|
|
70
|
+
}
|
|
71
|
+
this.morphTypeKey = typeAttr;
|
|
72
|
+
this.morphTypeColumnName = typeColDef.columnName;
|
|
73
|
+
this.morphIdKey = idAttr;
|
|
74
|
+
this.morphIdColumnName = idColDef.columnName;
|
|
75
|
+
// Build the reverse map for associate(): ModelClass -> type string
|
|
76
|
+
if (this.morphMap) {
|
|
77
|
+
for (const [morphType, factory] of Object.entries(this.morphMap)) {
|
|
78
|
+
const ModelClass = factory();
|
|
79
|
+
this.reverseMorphMap.set(ModelClass, morphType);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
this.booted = true;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolves the model factory for a given morph type string.
|
|
86
|
+
* Checks the explicit morphMap first, then falls back to the global registry.
|
|
87
|
+
*/
|
|
88
|
+
resolveModelFactory(morphType) {
|
|
89
|
+
if (this.morphMap?.[morphType]) {
|
|
90
|
+
return this.morphMap[morphType];
|
|
91
|
+
}
|
|
92
|
+
const registry = getRegistry();
|
|
93
|
+
if (registry?.has(morphType)) {
|
|
94
|
+
return () => registry.get(morphType);
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Looks up the morph type string for a given model class.
|
|
100
|
+
* Checks the explicit reverse map first, then falls back to the global registry.
|
|
101
|
+
* Used by MorphToQueryClient.associate().
|
|
102
|
+
*/
|
|
103
|
+
getMorphTypeFor(ModelClass) {
|
|
104
|
+
const fromMap = this.reverseMorphMap.get(ModelClass);
|
|
105
|
+
if (fromMap)
|
|
106
|
+
return fromMap;
|
|
107
|
+
try {
|
|
108
|
+
return getRegistry()?.getAlias(ModelClass);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
setRelated(parent, related) {
|
|
115
|
+
if (related === undefined)
|
|
116
|
+
return;
|
|
117
|
+
parent.$setRelated(this.relationName, related);
|
|
118
|
+
}
|
|
119
|
+
pushRelated(parent, related) {
|
|
120
|
+
if (related === undefined)
|
|
121
|
+
return;
|
|
122
|
+
parent.$setRelated(this.relationName, related);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Matches and sets related models on each parent during eager loading.
|
|
126
|
+
* Uses __morphType and __morphPk stored in $extras by MorphToEagerLoader.exec().
|
|
127
|
+
*/
|
|
128
|
+
setRelatedForMany(parents, related) {
|
|
129
|
+
parents.forEach((parentModel) => {
|
|
130
|
+
const morphType = parentModel[this.morphTypeKey];
|
|
131
|
+
const morphId = parentModel[this.morphIdKey];
|
|
132
|
+
if (!morphType || morphId == null) {
|
|
133
|
+
this.setRelated(parentModel, null);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const match = related.find((r) => r.$extras.__morphType === morphType &&
|
|
137
|
+
// Use loose comparison to handle number/string mismatch
|
|
138
|
+
// eslint-disable-next-line eqeqeq
|
|
139
|
+
r.$extras.__morphPk == morphId);
|
|
140
|
+
this.setRelated(parentModel, match ?? null);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
client(parent, client) {
|
|
144
|
+
if (!this.booted)
|
|
145
|
+
this.boot();
|
|
146
|
+
return new MorphToQueryClient(this, parent, client);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Returns the eager loader (used by the Lucid preloader).
|
|
150
|
+
* For a single parent, wrap it in an array for unified handling.
|
|
151
|
+
*/
|
|
152
|
+
eagerQuery(parent, client) {
|
|
153
|
+
if (!this.booted)
|
|
154
|
+
this.boot();
|
|
155
|
+
const parents = Array.isArray(parent) ? parent : [parent];
|
|
156
|
+
return new MorphToEagerLoader(client, this, parents);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* MorphTo subqueries are not supported.
|
|
160
|
+
*/
|
|
161
|
+
subQuery(_client) {
|
|
162
|
+
throw new Error(`morphTo: whereHas/withCount is not yet supported for polymorphic relations ("${this.relationName}")`);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* MorphTo does not hydrate for persistence (the child model owns the FK columns
|
|
166
|
+
* and they are set via associate() or directly by the user).
|
|
167
|
+
*/
|
|
168
|
+
hydrateForPersistance(_parent, _related) {
|
|
169
|
+
// No-op: for morphTo the child model holds the FK, not the parent
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/relations/morph_to/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { MorphTo } from './index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Query client for morphTo - provides read and write methods
|
|
4
|
+
* for the polymorphic "belongs to" side.
|
|
5
|
+
*/
|
|
6
|
+
export declare class MorphToQueryClient {
|
|
7
|
+
private relation;
|
|
8
|
+
private parent;
|
|
9
|
+
private client;
|
|
10
|
+
constructor(relation: MorphTo, parent: any, client: any);
|
|
11
|
+
/**
|
|
12
|
+
* Returns a query builder scoped to the related model.
|
|
13
|
+
* The related model is determined dynamically from the parent's morph type value.
|
|
14
|
+
*/
|
|
15
|
+
query(): any;
|
|
16
|
+
/**
|
|
17
|
+
* Associates this model with a related model instance by setting the
|
|
18
|
+
* morph type and morph id columns and saving.
|
|
19
|
+
*/
|
|
20
|
+
associate(related: any): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Dissociates this model from its current related model by nulling out
|
|
23
|
+
* the morph type and morph id columns.
|
|
24
|
+
*/
|
|
25
|
+
dissociate(): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=query_client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query_client.d.ts","sourceRoot":"","sources":["../../../../src/relations/morph_to/query_client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEzC;;;GAGG;AACH,qBAAa,kBAAkB;IAE3B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;gBAFN,QAAQ,EAAE,OAAO,EACjB,MAAM,EAAE,GAAG,EACX,MAAM,EAAE,GAAG;IAGrB;;;OAGG;IACH,KAAK,IAAI,GAAG;IAuBZ;;;OAGG;IACG,SAAS,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB5C;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAQlC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { managedTransaction } from '@adonisjs/lucid/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Query client for morphTo - provides read and write methods
|
|
4
|
+
* for the polymorphic "belongs to" side.
|
|
5
|
+
*/
|
|
6
|
+
export class MorphToQueryClient {
|
|
7
|
+
relation;
|
|
8
|
+
parent;
|
|
9
|
+
client;
|
|
10
|
+
constructor(relation, parent, client) {
|
|
11
|
+
this.relation = relation;
|
|
12
|
+
this.parent = parent;
|
|
13
|
+
this.client = client;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Returns a query builder scoped to the related model.
|
|
17
|
+
* The related model is determined dynamically from the parent's morph type value.
|
|
18
|
+
*/
|
|
19
|
+
query() {
|
|
20
|
+
const morphType = this.parent[this.relation.morphTypeKey];
|
|
21
|
+
const morphId = this.parent[this.relation.morphIdKey];
|
|
22
|
+
if (!morphType) {
|
|
23
|
+
throw new Error(`Cannot query "${this.relation.relationName}": ` +
|
|
24
|
+
`"${this.relation.model.name}.${this.relation.morphTypeKey}" is null or undefined`);
|
|
25
|
+
}
|
|
26
|
+
const modelFactory = this.relation.resolveModelFactory(morphType);
|
|
27
|
+
if (!modelFactory) {
|
|
28
|
+
throw new Error(`[MorphTo] Unknown morph type "${morphType}" for relation "${this.relation.relationName}". ` +
|
|
29
|
+
`Add it to the morphMap option or decorate the model with @MorphMap('${morphType}').`);
|
|
30
|
+
}
|
|
31
|
+
const RelatedModel = modelFactory();
|
|
32
|
+
return RelatedModel.query({ client: this.client }).where(RelatedModel.primaryKey, morphId);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Associates this model with a related model instance by setting the
|
|
36
|
+
* morph type and morph id columns and saving.
|
|
37
|
+
*/
|
|
38
|
+
async associate(related) {
|
|
39
|
+
await managedTransaction(this.parent.$trx || this.client, async (trx) => {
|
|
40
|
+
const morphType = this.relation.getMorphTypeFor(related.constructor);
|
|
41
|
+
if (!morphType) {
|
|
42
|
+
throw new Error(`[MorphTo] Cannot associate: model "${related.constructor.name}" is not in the morphMap ` +
|
|
43
|
+
`for relation "${this.relation.relationName}".`);
|
|
44
|
+
}
|
|
45
|
+
this.parent[this.relation.morphTypeKey] = morphType;
|
|
46
|
+
this.parent[this.relation.morphIdKey] = related[related.constructor.primaryKey];
|
|
47
|
+
this.parent.$trx = trx;
|
|
48
|
+
await this.parent.save();
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Dissociates this model from its current related model by nulling out
|
|
53
|
+
* the morph type and morph id columns.
|
|
54
|
+
*/
|
|
55
|
+
async dissociate() {
|
|
56
|
+
await managedTransaction(this.parent.$trx || this.client, async (trx) => {
|
|
57
|
+
this.parent[this.relation.morphTypeKey] = null;
|
|
58
|
+
this.parent[this.relation.morphIdKey] = null;
|
|
59
|
+
this.parent.$trx = trx;
|
|
60
|
+
await this.parent.save();
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=query_client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query_client.js","sourceRoot":"","sources":["../../../../src/relations/morph_to/query_client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../../src/relations/morph_to/registry.ts"],"names":[],"mappings":"AAUA,wBAAgB,WAAW,oDAE1B"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global morph map registry from @holoyan/morph-map-js.
|
|
3
|
+
*
|
|
4
|
+
* Always available as a direct dependency. Usage is optional —
|
|
5
|
+
* decorate models with @MorphMap('posts') to register them, or
|
|
6
|
+
* keep using the explicit morphMap option on @morphTo instead.
|
|
7
|
+
* If no @MorphMap decorators are used the registry is simply empty.
|
|
8
|
+
*/
|
|
9
|
+
import { morphMap } from '@holoyan/morph-map-js';
|
|
10
|
+
export function getRegistry() {
|
|
11
|
+
return morphMap;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../../src/relations/morph_to/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAEhD,MAAM,UAAU,WAAW;IACzB,OAAO,QAAQ,CAAA;AACjB,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ModelQueryBuilder } from '@adonisjs/lucid/orm';
|
|
2
|
+
/**
|
|
3
|
+
* Shared base for morphOne and morphMany query builders.
|
|
4
|
+
* Extends Lucid's ModelQueryBuilder and adds the boilerplate needed
|
|
5
|
+
* to act as a relation query builder (applyConstraints, selectRelationKeys, etc.)
|
|
6
|
+
*/
|
|
7
|
+
export declare abstract class MorphBaseQueryBuilder extends ModelQueryBuilder {
|
|
8
|
+
/**
|
|
9
|
+
* Marks this as a relation eager-load query when set by the query client.
|
|
10
|
+
*/
|
|
11
|
+
isRelatedPreloadQuery: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Guards against applying constraints more than once.
|
|
14
|
+
*/
|
|
15
|
+
protected appliedConstraints: boolean;
|
|
16
|
+
get isRelatedQuery(): boolean;
|
|
17
|
+
get isRelatedSubQuery(): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Returns the names of the columns that must always be selected
|
|
20
|
+
* so that setRelatedForMany() can match rows to parent models.
|
|
21
|
+
*/
|
|
22
|
+
abstract getRelationKeys(): string[];
|
|
23
|
+
/**
|
|
24
|
+
* Returns data used by the query profiler / logger.
|
|
25
|
+
*/
|
|
26
|
+
abstract profilerData(): Record<string, any>;
|
|
27
|
+
/**
|
|
28
|
+
* Applies the WHERE conditions that scope this query to the relation.
|
|
29
|
+
* Called lazily before exec/toSQL/first.
|
|
30
|
+
*/
|
|
31
|
+
abstract applyConstraints(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Dis-allow groupLimit. Subclasses may throw.
|
|
34
|
+
*/
|
|
35
|
+
abstract getGroupLimitQuery(): any;
|
|
36
|
+
/**
|
|
37
|
+
* Reads the currently selected columns from the underlying knex query.
|
|
38
|
+
* Knex stores these in an internal _statements array.
|
|
39
|
+
*/
|
|
40
|
+
private getSelectedColumns;
|
|
41
|
+
/**
|
|
42
|
+
* Ensures that the morph id column is always included in SELECT so that
|
|
43
|
+
* setRelatedForMany() can match rows to parent models.
|
|
44
|
+
*/
|
|
45
|
+
selectRelationKeys(): this;
|
|
46
|
+
/**
|
|
47
|
+
* Returns the current query action string ('select', 'preload', 'update', 'delete').
|
|
48
|
+
* Used only for descriptive error messages.
|
|
49
|
+
*/
|
|
50
|
+
protected queryAction(): string;
|
|
51
|
+
toSQL(): import("knex").Knex.Sql;
|
|
52
|
+
exec(): Promise<any[]>;
|
|
53
|
+
first(): Promise<any>;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=query_builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query_builder.d.ts","sourceRoot":"","sources":["../../../../src/relations/shared/query_builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD;;;;GAIG;AACH,8BAAsB,qBAAsB,SAAQ,iBAAiB;IACnE;;OAEG;IACH,qBAAqB,EAAE,OAAO,CAAQ;IAEtC;;OAEG;IACH,SAAS,CAAC,kBAAkB,EAAE,OAAO,CAAQ;IAE7C,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAED;;;OAGG;IACH,QAAQ,CAAC,eAAe,IAAI,MAAM,EAAE;IAEpC;;OAEG;IACH,QAAQ,CAAC,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAE5C;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,IAAI,IAAI;IAEjC;;OAEG;IACH,QAAQ,CAAC,kBAAkB,IAAI,GAAG;IAElC;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;;OAGG;IACH,kBAAkB,IAAI,IAAI;IAc1B;;;OAGG;IACH,SAAS,CAAC,WAAW,IAAI,MAAM;IAO/B,KAAK;IAKL,IAAI;IAKJ,KAAK;CAIN"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ModelQueryBuilder } from '@adonisjs/lucid/orm';
|
|
2
|
+
/**
|
|
3
|
+
* Shared base for morphOne and morphMany query builders.
|
|
4
|
+
* Extends Lucid's ModelQueryBuilder and adds the boilerplate needed
|
|
5
|
+
* to act as a relation query builder (applyConstraints, selectRelationKeys, etc.)
|
|
6
|
+
*/
|
|
7
|
+
export class MorphBaseQueryBuilder extends ModelQueryBuilder {
|
|
8
|
+
/**
|
|
9
|
+
* Marks this as a relation eager-load query when set by the query client.
|
|
10
|
+
*/
|
|
11
|
+
isRelatedPreloadQuery = false;
|
|
12
|
+
/**
|
|
13
|
+
* Guards against applying constraints more than once.
|
|
14
|
+
*/
|
|
15
|
+
appliedConstraints = false;
|
|
16
|
+
get isRelatedQuery() {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
get isRelatedSubQuery() {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Reads the currently selected columns from the underlying knex query.
|
|
24
|
+
* Knex stores these in an internal _statements array.
|
|
25
|
+
*/
|
|
26
|
+
getSelectedColumns() {
|
|
27
|
+
return this.knexQuery['_statements'].find(({ grouping }) => grouping === 'columns');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Ensures that the morph id column is always included in SELECT so that
|
|
31
|
+
* setRelatedForMany() can match rows to parent models.
|
|
32
|
+
*/
|
|
33
|
+
selectRelationKeys() {
|
|
34
|
+
const columns = this.getSelectedColumns();
|
|
35
|
+
if (!columns)
|
|
36
|
+
return this;
|
|
37
|
+
this.getRelationKeys().forEach((key) => {
|
|
38
|
+
const resolved = this.resolveKey(key);
|
|
39
|
+
if (!columns.value.includes(resolved)) {
|
|
40
|
+
columns.value.push(resolved);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Returns the current query action string ('select', 'preload', 'update', 'delete').
|
|
47
|
+
* Used only for descriptive error messages.
|
|
48
|
+
*/
|
|
49
|
+
queryAction() {
|
|
50
|
+
const method = this.knexQuery['_method'];
|
|
51
|
+
if (method === 'del')
|
|
52
|
+
return 'delete';
|
|
53
|
+
if (method === 'select' && this.isRelatedPreloadQuery)
|
|
54
|
+
return 'preload';
|
|
55
|
+
return method ?? 'select';
|
|
56
|
+
}
|
|
57
|
+
toSQL() {
|
|
58
|
+
this.applyConstraints();
|
|
59
|
+
return super.toSQL();
|
|
60
|
+
}
|
|
61
|
+
exec() {
|
|
62
|
+
this.applyConstraints();
|
|
63
|
+
return super.exec();
|
|
64
|
+
}
|
|
65
|
+
first() {
|
|
66
|
+
this.applyConstraints();
|
|
67
|
+
return super.first();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=query_builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query_builder.js","sourceRoot":"","sources":["../../../../src/relations/shared/query_builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD;;;;GAIG;AACH,MAAM,OAAgB,qBAAsB,SAAQ,iBAAiB;IACnE;;OAEG;IACH,qBAAqB,GAAY,KAAK,CAAA;IAEtC;;OAEG;IACO,kBAAkB,GAAY,KAAK,CAAA;IAE7C,IAAI,cAAc;QAChB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,iBAAiB;QACnB,OAAO,KAAK,CAAA;IACd,CAAC;IAwBD;;;OAGG;IACK,kBAAkB;QACxB,OAAQ,IAAI,CAAC,SAAiB,CAAC,aAAa,CAAC,CAAC,IAAI,CAChD,CAAC,EAAE,QAAQ,EAAwB,EAAE,EAAE,CAAC,QAAQ,KAAK,SAAS,CAC5B,CAAA;IACtC,CAAC;IAED;;;OAGG;IACH,kBAAkB;QAChB,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAA;QACzC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QAEzB,IAAI,CAAC,eAAe,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YACrC,MAAM,QAAQ,GAAI,IAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;YAC9C,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACtC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC9B,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;OAGG;IACO,WAAW;QACnB,MAAM,MAAM,GAAI,IAAI,CAAC,SAAiB,CAAC,SAAS,CAAuB,CAAA;QACvE,IAAI,MAAM,KAAK,KAAK;YAAE,OAAO,QAAQ,CAAA;QACrC,IAAI,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,qBAAqB;YAAE,OAAO,SAAS,CAAA;QACvE,OAAO,MAAM,IAAI,QAAQ,CAAA;IAC3B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,gBAAgB,EAAE,CAAA;QACvB,OAAO,KAAK,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,gBAAgB,EAAE,CAAA;QACvB,OAAO,KAAK,CAAC,IAAI,EAAE,CAAA;IACrB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,gBAAgB,EAAE,CAAA;QACvB,OAAO,KAAK,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;CACF"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options accepted by morphOne and morphMany relations.
|
|
3
|
+
* These are defined on the "parent" model (the one that owns the polymorphic children).
|
|
4
|
+
*/
|
|
5
|
+
export interface MorphOneOptions {
|
|
6
|
+
/**
|
|
7
|
+
* The morph name prefix used to derive type and id column names on the related model.
|
|
8
|
+
* Example: name: 'imageable' -> attributes 'imageableType' and 'imageableId' on related model
|
|
9
|
+
* which map to columns 'imageable_type' and 'imageable_id' in the DB
|
|
10
|
+
*/
|
|
11
|
+
name: string;
|
|
12
|
+
/**
|
|
13
|
+
* The local key attribute on the parent model.
|
|
14
|
+
* Defaults to the parent model's primary key.
|
|
15
|
+
*/
|
|
16
|
+
localKey?: string;
|
|
17
|
+
/**
|
|
18
|
+
* The value stored in the morph type column to identify this parent model.
|
|
19
|
+
* Defaults to the parent model's table name (e.g., 'posts').
|
|
20
|
+
*/
|
|
21
|
+
morphValue?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Serialize as key. Set to null to exclude from serialization.
|
|
24
|
+
*/
|
|
25
|
+
serializeAs?: string | null;
|
|
26
|
+
/**
|
|
27
|
+
* Hook to add custom query constraints to all queries for this relation.
|
|
28
|
+
*/
|
|
29
|
+
onQuery?: (query: any) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Extra meta data attached to the relation. Not used internally.
|
|
32
|
+
*/
|
|
33
|
+
meta?: any;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Options accepted by morphMany. Same as morphOne.
|
|
37
|
+
*/
|
|
38
|
+
export interface MorphManyOptions extends MorphOneOptions {
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Options accepted by morphTo relations.
|
|
42
|
+
* These are defined on the "child" model (the one that holds the type and id columns).
|
|
43
|
+
*/
|
|
44
|
+
export interface MorphToOptions {
|
|
45
|
+
/**
|
|
46
|
+
* Maps morph type string values to model factories.
|
|
47
|
+
* Example: { posts: () => Post, videos: () => Video }
|
|
48
|
+
*
|
|
49
|
+
* Optional when @holoyan/morph-map-js is installed and models are
|
|
50
|
+
* decorated with @MorphMap('posts') — the global registry is used
|
|
51
|
+
* as a fallback at query time.
|
|
52
|
+
*/
|
|
53
|
+
morphMap?: Record<string, () => any>;
|
|
54
|
+
/**
|
|
55
|
+
* The morph name prefix used to derive type and id attribute names on THIS model.
|
|
56
|
+
* Example: name: 'commentable' -> attributes 'commentableType' and 'commentableId'
|
|
57
|
+
* Defaults to the relation name.
|
|
58
|
+
*/
|
|
59
|
+
name?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Explicit attribute name for the type column on this model.
|
|
62
|
+
* Overrides the name-derived attribute.
|
|
63
|
+
*/
|
|
64
|
+
typeKey?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Explicit attribute name for the id column on this model.
|
|
67
|
+
* Overrides the name-derived attribute.
|
|
68
|
+
*/
|
|
69
|
+
idKey?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Serialize as key. Set to null to exclude from serialization.
|
|
72
|
+
*/
|
|
73
|
+
serializeAs?: string | null;
|
|
74
|
+
/**
|
|
75
|
+
* Hook to add custom query constraints. Note: for MorphTo this is limited
|
|
76
|
+
* since the target model is dynamic.
|
|
77
|
+
*/
|
|
78
|
+
onQuery?: (query: any) => void;
|
|
79
|
+
/**
|
|
80
|
+
* Extra meta data attached to the relation.
|
|
81
|
+
*/
|
|
82
|
+
meta?: any;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAA;IAEZ;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAE3B;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAA;IAE9B;;OAEG;IACH,IAAI,CAAC,EAAE,GAAG,CAAA;CACX;AAED;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,eAAe;CAAG;AAE5D;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAA;IAEpC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAE3B;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAA;IAE9B;;OAEG;IACH,IAAI,CAAC,EAAE,GAAG,CAAA;CACX"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{{{
|
|
2
|
+
exports({ to: app.configPath('polymorphic.ts') })
|
|
3
|
+
}}}
|
|
4
|
+
import { defineConfig } from '@holoyan/adonisjs-polymorphic'
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
/**
|
|
8
|
+
* List every model decorated with @MorphMap here.
|
|
9
|
+
* The service provider imports them at boot time so the global
|
|
10
|
+
* registry is populated before any query runs.
|
|
11
|
+
*
|
|
12
|
+
* Example:
|
|
13
|
+
* morphModels: [
|
|
14
|
+
* () => import('#models/post'),
|
|
15
|
+
* () => import('#models/video'),
|
|
16
|
+
* ],
|
|
17
|
+
*/
|
|
18
|
+
morphModels: [],
|
|
19
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../stubs/main.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,SAAS,QAAsB,CAAA"}
|