metal-orm 1.1.9 → 1.1.11
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 +769 -764
- package/dist/index.cjs +2255 -284
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +559 -39
- package/dist/index.d.ts +559 -39
- package/dist/index.js +2227 -284
- package/dist/index.js.map +1 -1
- package/package.json +17 -12
- package/scripts/generate-entities/render.mjs +21 -12
- package/scripts/generate-entities/schema.mjs +87 -73
- package/scripts/generate-entities/tree-detection.mjs +67 -61
- package/src/bulk/bulk-context.ts +83 -0
- package/src/bulk/bulk-delete-executor.ts +87 -0
- package/src/bulk/bulk-executor.base.ts +73 -0
- package/src/bulk/bulk-insert-executor.ts +74 -0
- package/src/bulk/bulk-types.ts +70 -0
- package/src/bulk/bulk-update-executor.ts +192 -0
- package/src/bulk/bulk-upsert-executor.ts +93 -0
- package/src/bulk/bulk-utils.ts +91 -0
- package/src/bulk/index.ts +18 -0
- package/src/codegen/typescript.ts +30 -21
- package/src/core/ast/expression-builders.ts +107 -10
- package/src/core/ast/expression-nodes.ts +52 -22
- package/src/core/ast/expression-visitor.ts +23 -13
- package/src/core/ddl/introspect/mysql.ts +113 -36
- package/src/core/dialect/abstract.ts +30 -17
- package/src/core/dialect/mysql/index.ts +20 -5
- package/src/core/execution/db-executor.ts +96 -64
- package/src/core/execution/executors/better-sqlite3-executor.ts +94 -0
- package/src/core/execution/executors/mssql-executor.ts +66 -34
- package/src/core/execution/executors/mysql-executor.ts +98 -66
- package/src/core/execution/executors/postgres-executor.ts +33 -11
- package/src/core/execution/executors/sqlite-executor.ts +86 -30
- package/src/decorators/bootstrap.ts +482 -398
- package/src/decorators/column-decorator.ts +87 -96
- package/src/decorators/decorator-metadata.ts +100 -24
- package/src/decorators/entity.ts +27 -24
- package/src/decorators/relations.ts +231 -149
- package/src/decorators/transformers/transformer-decorators.ts +26 -29
- package/src/decorators/validators/country-validators-decorators.ts +9 -15
- package/src/dto/apply-filter.ts +568 -551
- package/src/index.ts +16 -9
- package/src/orm/entity-hydration.ts +116 -72
- package/src/orm/entity-metadata.ts +347 -301
- package/src/orm/entity-relations.ts +264 -207
- package/src/orm/entity.ts +199 -199
- package/src/orm/execute.ts +13 -13
- package/src/orm/lazy-batch/morph-many.ts +70 -0
- package/src/orm/lazy-batch/morph-one.ts +69 -0
- package/src/orm/lazy-batch/morph-to.ts +59 -0
- package/src/orm/lazy-batch.ts +4 -1
- package/src/orm/orm-session.ts +170 -104
- package/src/orm/pooled-executor-factory.ts +99 -58
- package/src/orm/query-logger.ts +49 -40
- package/src/orm/relation-change-processor.ts +198 -96
- package/src/orm/relations/belongs-to.ts +143 -143
- package/src/orm/relations/has-many.ts +204 -204
- package/src/orm/relations/has-one.ts +174 -174
- package/src/orm/relations/many-to-many.ts +288 -288
- package/src/orm/relations/morph-many.ts +156 -0
- package/src/orm/relations/morph-one.ts +151 -0
- package/src/orm/relations/morph-to.ts +162 -0
- package/src/orm/save-graph.ts +116 -1
- package/src/query-builder/expression-table-mapper.ts +5 -0
- package/src/query-builder/hydration-manager.ts +345 -345
- package/src/query-builder/hydration-planner.ts +178 -148
- package/src/query-builder/relation-conditions.ts +171 -151
- package/src/query-builder/relation-cte-builder.ts +5 -1
- package/src/query-builder/relation-filter-utils.ts +9 -6
- package/src/query-builder/relation-include-strategies.ts +44 -2
- package/src/query-builder/relation-join-strategies.ts +8 -1
- package/src/query-builder/relation-service.ts +250 -241
- package/src/query-builder/select/select-operations.ts +110 -105
- package/src/query-builder/update-include.ts +4 -0
- package/src/schema/relation.ts +296 -188
- package/src/schema/types.ts +138 -123
- package/src/tree/tree-decorator.ts +127 -137
package/src/schema/relation.ts
CHANGED
|
@@ -1,188 +1,296 @@
|
|
|
1
|
-
import type { TableDef } from './table.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Types of relationships supported between tables
|
|
5
|
-
*/
|
|
6
|
-
export const RelationKinds = {
|
|
7
|
-
/** One-to-one relationship */
|
|
8
|
-
HasOne: 'HAS_ONE',
|
|
9
|
-
/** One-to-many relationship */
|
|
10
|
-
HasMany: 'HAS_MANY',
|
|
11
|
-
/** Many-to-one relationship */
|
|
12
|
-
BelongsTo: 'BELONGS_TO',
|
|
13
|
-
/** Many-to-many relationship with pivot metadata */
|
|
14
|
-
BelongsToMany: 'BELONGS_TO_MANY'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
*
|
|
137
|
-
* @
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
1
|
+
import type { TableDef } from './table.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Types of relationships supported between tables
|
|
5
|
+
*/
|
|
6
|
+
export const RelationKinds = {
|
|
7
|
+
/** One-to-one relationship */
|
|
8
|
+
HasOne: 'HAS_ONE',
|
|
9
|
+
/** One-to-many relationship */
|
|
10
|
+
HasMany: 'HAS_MANY',
|
|
11
|
+
/** Many-to-one relationship */
|
|
12
|
+
BelongsTo: 'BELONGS_TO',
|
|
13
|
+
/** Many-to-many relationship with pivot metadata */
|
|
14
|
+
BelongsToMany: 'BELONGS_TO_MANY',
|
|
15
|
+
/** Polymorphic inverse (child side) */
|
|
16
|
+
MorphTo: 'MORPH_TO',
|
|
17
|
+
/** Polymorphic one-to-one (parent side) */
|
|
18
|
+
MorphOne: 'MORPH_ONE',
|
|
19
|
+
/** Polymorphic one-to-many (parent side) */
|
|
20
|
+
MorphMany: 'MORPH_MANY'
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Type representing the supported relationship kinds
|
|
25
|
+
*/
|
|
26
|
+
export type RelationType = (typeof RelationKinds)[keyof typeof RelationKinds];
|
|
27
|
+
|
|
28
|
+
export type CascadeMode = 'none' | 'all' | 'persist' | 'remove' | 'link';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* One-to-many relationship definition
|
|
32
|
+
*/
|
|
33
|
+
export interface HasManyRelation<TTarget extends TableDef = TableDef> {
|
|
34
|
+
type: typeof RelationKinds.HasMany;
|
|
35
|
+
target: TTarget;
|
|
36
|
+
foreignKey: string;
|
|
37
|
+
localKey?: string;
|
|
38
|
+
cascade?: CascadeMode;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* One-to-one relationship definition
|
|
43
|
+
*/
|
|
44
|
+
export interface HasOneRelation<TTarget extends TableDef = TableDef> {
|
|
45
|
+
type: typeof RelationKinds.HasOne;
|
|
46
|
+
target: TTarget;
|
|
47
|
+
foreignKey: string;
|
|
48
|
+
localKey?: string;
|
|
49
|
+
cascade?: CascadeMode;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Many-to-one relationship definition
|
|
54
|
+
*/
|
|
55
|
+
export interface BelongsToRelation<TTarget extends TableDef = TableDef> {
|
|
56
|
+
type: typeof RelationKinds.BelongsTo;
|
|
57
|
+
target: TTarget;
|
|
58
|
+
foreignKey: string;
|
|
59
|
+
localKey?: string;
|
|
60
|
+
cascade?: CascadeMode;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Many-to-many relationship definition with rich pivot metadata
|
|
65
|
+
*/
|
|
66
|
+
export interface BelongsToManyRelation<
|
|
67
|
+
TTarget extends TableDef = TableDef,
|
|
68
|
+
TPivot extends TableDef = TableDef
|
|
69
|
+
> {
|
|
70
|
+
type: typeof RelationKinds.BelongsToMany;
|
|
71
|
+
target: TTarget;
|
|
72
|
+
pivotTable: TPivot;
|
|
73
|
+
pivotForeignKeyToRoot: string;
|
|
74
|
+
pivotForeignKeyToTarget: string;
|
|
75
|
+
localKey?: string;
|
|
76
|
+
targetKey?: string;
|
|
77
|
+
pivotPrimaryKey?: string;
|
|
78
|
+
defaultPivotColumns?: string[];
|
|
79
|
+
cascade?: CascadeMode;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Polymorphic inverse relationship (child side).
|
|
84
|
+
* The child row stores a type + id pair that can point to any of the listed targets.
|
|
85
|
+
*/
|
|
86
|
+
export interface MorphToRelation<TTargets extends Record<string, TableDef> = Record<string, TableDef>> {
|
|
87
|
+
type: typeof RelationKinds.MorphTo;
|
|
88
|
+
typeField: string;
|
|
89
|
+
idField: string;
|
|
90
|
+
targets: TTargets;
|
|
91
|
+
targetKey?: string;
|
|
92
|
+
cascade?: CascadeMode;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Polymorphic one-to-one relationship (parent side).
|
|
97
|
+
*/
|
|
98
|
+
export interface MorphOneRelation<TTarget extends TableDef = TableDef> {
|
|
99
|
+
type: typeof RelationKinds.MorphOne;
|
|
100
|
+
target: TTarget;
|
|
101
|
+
morphName: string;
|
|
102
|
+
typeField: string;
|
|
103
|
+
idField: string;
|
|
104
|
+
typeValue: string;
|
|
105
|
+
localKey?: string;
|
|
106
|
+
cascade?: CascadeMode;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Polymorphic one-to-many relationship (parent side).
|
|
111
|
+
*/
|
|
112
|
+
export interface MorphManyRelation<TTarget extends TableDef = TableDef> {
|
|
113
|
+
type: typeof RelationKinds.MorphMany;
|
|
114
|
+
target: TTarget;
|
|
115
|
+
morphName: string;
|
|
116
|
+
typeField: string;
|
|
117
|
+
idField: string;
|
|
118
|
+
typeValue: string;
|
|
119
|
+
localKey?: string;
|
|
120
|
+
cascade?: CascadeMode;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Union type representing any supported relationship definition
|
|
125
|
+
*/
|
|
126
|
+
export type RelationDef =
|
|
127
|
+
| HasManyRelation
|
|
128
|
+
| HasOneRelation
|
|
129
|
+
| BelongsToRelation
|
|
130
|
+
| BelongsToManyRelation
|
|
131
|
+
| MorphToRelation
|
|
132
|
+
| MorphOneRelation
|
|
133
|
+
| MorphManyRelation;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Creates a one-to-many relationship definition
|
|
137
|
+
* @param target - Target table of the relationship
|
|
138
|
+
* @param foreignKey - Foreign key column name on the child table
|
|
139
|
+
* @param localKey - Local key column name (optional)
|
|
140
|
+
* @returns HasManyRelation definition
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* hasMany(usersTable, 'user_id')
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export const hasMany = <TTarget extends TableDef>(
|
|
148
|
+
target: TTarget,
|
|
149
|
+
foreignKey: string,
|
|
150
|
+
localKey?: string,
|
|
151
|
+
cascade?: CascadeMode
|
|
152
|
+
): HasManyRelation<TTarget> => ({
|
|
153
|
+
type: RelationKinds.HasMany,
|
|
154
|
+
target,
|
|
155
|
+
foreignKey,
|
|
156
|
+
localKey,
|
|
157
|
+
cascade
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Creates a one-to-one relationship definition
|
|
162
|
+
* @param target - Target table of the relationship
|
|
163
|
+
* @param foreignKey - Foreign key column name on the child table
|
|
164
|
+
* @param localKey - Local key column name (optional)
|
|
165
|
+
* @returns HasOneRelation definition
|
|
166
|
+
*/
|
|
167
|
+
export const hasOne = <TTarget extends TableDef>(
|
|
168
|
+
target: TTarget,
|
|
169
|
+
foreignKey: string,
|
|
170
|
+
localKey?: string,
|
|
171
|
+
cascade?: CascadeMode
|
|
172
|
+
): HasOneRelation<TTarget> => ({
|
|
173
|
+
type: RelationKinds.HasOne,
|
|
174
|
+
target,
|
|
175
|
+
foreignKey,
|
|
176
|
+
localKey,
|
|
177
|
+
cascade
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Creates a many-to-one relationship definition
|
|
182
|
+
* @param target - Target table of the relationship
|
|
183
|
+
* @param foreignKey - Foreign key column name on the child table
|
|
184
|
+
* @param localKey - Local key column name (optional)
|
|
185
|
+
* @returns BelongsToRelation definition
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* belongsTo(usersTable, 'user_id')
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
export const belongsTo = <TTarget extends TableDef>(
|
|
193
|
+
target: TTarget,
|
|
194
|
+
foreignKey: string,
|
|
195
|
+
localKey?: string,
|
|
196
|
+
cascade?: CascadeMode
|
|
197
|
+
): BelongsToRelation<TTarget> => ({
|
|
198
|
+
type: RelationKinds.BelongsTo,
|
|
199
|
+
target,
|
|
200
|
+
foreignKey,
|
|
201
|
+
localKey,
|
|
202
|
+
cascade
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Creates a many-to-many relationship definition with pivot metadata
|
|
207
|
+
* @param target - Target table
|
|
208
|
+
* @param pivotTable - Intermediate pivot table definition
|
|
209
|
+
* @param options - Pivot metadata configuration
|
|
210
|
+
* @returns BelongsToManyRelation definition
|
|
211
|
+
*/
|
|
212
|
+
export const belongsToMany = <
|
|
213
|
+
TTarget extends TableDef,
|
|
214
|
+
TPivot extends TableDef = TableDef
|
|
215
|
+
>(
|
|
216
|
+
target: TTarget,
|
|
217
|
+
pivotTable: TPivot,
|
|
218
|
+
options: {
|
|
219
|
+
pivotForeignKeyToRoot: string;
|
|
220
|
+
pivotForeignKeyToTarget: string;
|
|
221
|
+
localKey?: string;
|
|
222
|
+
targetKey?: string;
|
|
223
|
+
pivotPrimaryKey?: string;
|
|
224
|
+
defaultPivotColumns?: string[];
|
|
225
|
+
cascade?: CascadeMode;
|
|
226
|
+
}
|
|
227
|
+
): BelongsToManyRelation<TTarget, TPivot> => ({
|
|
228
|
+
type: RelationKinds.BelongsToMany,
|
|
229
|
+
target,
|
|
230
|
+
pivotTable,
|
|
231
|
+
pivotForeignKeyToRoot: options.pivotForeignKeyToRoot,
|
|
232
|
+
pivotForeignKeyToTarget: options.pivotForeignKeyToTarget,
|
|
233
|
+
localKey: options.localKey,
|
|
234
|
+
targetKey: options.targetKey,
|
|
235
|
+
pivotPrimaryKey: options.pivotPrimaryKey,
|
|
236
|
+
defaultPivotColumns: options.defaultPivotColumns,
|
|
237
|
+
cascade: options.cascade
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
export const isSingleTargetRelation = (
|
|
241
|
+
rel: RelationDef
|
|
242
|
+
): rel is Exclude<RelationDef, MorphToRelation> =>
|
|
243
|
+
rel.type !== RelationKinds.MorphTo;
|
|
244
|
+
|
|
245
|
+
export const isMorphRelation = (rel: RelationDef): rel is
|
|
246
|
+
MorphToRelation | MorphOneRelation | MorphManyRelation =>
|
|
247
|
+
rel.type === RelationKinds.MorphTo ||
|
|
248
|
+
rel.type === RelationKinds.MorphOne ||
|
|
249
|
+
rel.type === RelationKinds.MorphMany;
|
|
250
|
+
|
|
251
|
+
export const morphTo = <TTargets extends Record<string, TableDef>>(opts: {
|
|
252
|
+
typeField: string;
|
|
253
|
+
idField: string;
|
|
254
|
+
targets: TTargets;
|
|
255
|
+
targetKey?: string;
|
|
256
|
+
cascade?: CascadeMode;
|
|
257
|
+
}): MorphToRelation<TTargets> => ({
|
|
258
|
+
type: RelationKinds.MorphTo,
|
|
259
|
+
...opts
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
export const morphOne = <TTarget extends TableDef>(target: TTarget, opts: {
|
|
263
|
+
as: string;
|
|
264
|
+
typeValue: string;
|
|
265
|
+
localKey?: string;
|
|
266
|
+
typeField?: string;
|
|
267
|
+
idField?: string;
|
|
268
|
+
cascade?: CascadeMode;
|
|
269
|
+
}): MorphOneRelation<TTarget> => ({
|
|
270
|
+
type: RelationKinds.MorphOne,
|
|
271
|
+
target,
|
|
272
|
+
morphName: opts.as,
|
|
273
|
+
typeField: opts.typeField ?? `${opts.as}Type`,
|
|
274
|
+
idField: opts.idField ?? `${opts.as}Id`,
|
|
275
|
+
typeValue: opts.typeValue,
|
|
276
|
+
localKey: opts.localKey,
|
|
277
|
+
cascade: opts.cascade
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
export const morphMany = <TTarget extends TableDef>(target: TTarget, opts: {
|
|
281
|
+
as: string;
|
|
282
|
+
typeValue: string;
|
|
283
|
+
localKey?: string;
|
|
284
|
+
typeField?: string;
|
|
285
|
+
idField?: string;
|
|
286
|
+
cascade?: CascadeMode;
|
|
287
|
+
}): MorphManyRelation<TTarget> => ({
|
|
288
|
+
type: RelationKinds.MorphMany,
|
|
289
|
+
target,
|
|
290
|
+
morphName: opts.as,
|
|
291
|
+
typeField: opts.typeField ?? `${opts.as}Type`,
|
|
292
|
+
idField: opts.idField ?? `${opts.as}Id`,
|
|
293
|
+
typeValue: opts.typeValue,
|
|
294
|
+
localKey: opts.localKey,
|
|
295
|
+
cascade: opts.cascade
|
|
296
|
+
});
|