vona-module-a-orm 5.1.39 → 5.1.41
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/dist/.metadata/index.d.ts +18 -18
- package/dist/.metadata/index.d.ts.map +1 -1
- package/dist/index.js +459 -58
- package/dist/index.js.map +1 -1
- package/dist/lib/aggregateResult.d.ts +7 -0
- package/dist/lib/aggregateResult.d.ts.map +1 -0
- package/dist/lib/analysis/controls.d.ts +27 -0
- package/dist/lib/analysis/controls.d.ts.map +1 -0
- package/dist/lib/analysis/execute.d.ts +6 -0
- package/dist/lib/analysis/execute.d.ts.map +1 -0
- package/dist/lib/analysis/index.d.ts +4 -0
- package/dist/lib/analysis/index.d.ts.map +1 -0
- package/dist/lib/analysis/policy.d.ts +6 -0
- package/dist/lib/analysis/policy.d.ts.map +1 -0
- package/dist/lib/bean.model/bean.model_cache.d.ts +4 -1
- package/dist/lib/bean.model/bean.model_cache.d.ts.map +1 -1
- package/dist/lib/bean.model/bean.model_crud_inner.d.ts +1 -1
- package/dist/lib/bean.model/bean.model_crud_inner.d.ts.map +1 -1
- package/dist/lib/dto/dto.d.ts +3 -0
- package/dist/lib/dto/dto.d.ts.map +1 -1
- package/dist/lib/dto/dtoAggregate.d.ts.map +1 -1
- package/dist/lib/dto/dtoAnalysis.d.ts +6 -0
- package/dist/lib/dto/dtoAnalysis.d.ts.map +1 -0
- package/dist/lib/dto/dtoCreate.d.ts +2 -2
- package/dist/lib/dto/dtoCreate.d.ts.map +1 -1
- package/dist/lib/dto/dtoGet.d.ts.map +1 -1
- package/dist/lib/dto/dtoMutate.d.ts +2 -2
- package/dist/lib/dto/dtoMutate.d.ts.map +1 -1
- package/dist/lib/dto/dtoUpdate.d.ts +2 -2
- package/dist/lib/dto/dtoUpdate.d.ts.map +1 -1
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/types/analysis.d.ts +105 -0
- package/dist/types/analysis.d.ts.map +1 -0
- package/dist/types/dto/dtoMutate.d.ts +28 -11
- package/dist/types/dto/dtoMutate.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/relationsAggr.d.ts +1 -1
- package/dist/types/relationsAggr.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/.metadata/index.ts +26 -26
- package/src/lib/aggregateResult.ts +53 -0
- package/src/lib/analysis/controls.ts +163 -0
- package/src/lib/analysis/execute.ts +49 -0
- package/src/lib/analysis/index.ts +3 -0
- package/src/lib/analysis/policy.ts +140 -0
- package/src/lib/bean.model/bean.model_cache.ts +96 -12
- package/src/lib/bean.model/bean.model_crud_inner.ts +8 -3
- package/src/lib/dto/dto.ts +3 -0
- package/src/lib/dto/dtoAggregate.ts +4 -1
- package/src/lib/dto/dtoAnalysis.ts +34 -0
- package/src/lib/dto/dtoCreate.ts +7 -9
- package/src/lib/dto/dtoGet.ts +27 -3
- package/src/lib/dto/dtoMutate.ts +2 -2
- package/src/lib/dto/dtoUpdate.ts +7 -9
- package/src/lib/index.ts +1 -0
- package/src/types/analysis.ts +137 -0
- package/src/types/dto/dtoMutate.ts +124 -87
- package/src/types/index.ts +1 -0
- package/src/types/relationsAggr.ts +1 -1
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
TypeModelWhere,
|
|
19
19
|
} from '../../types/index.ts';
|
|
20
20
|
|
|
21
|
+
import { normalizeAggregateRows, normalizeAggregateValue } from '../aggregateResult.ts';
|
|
21
22
|
import { BeanModelView } from './bean.model_view.ts';
|
|
22
23
|
|
|
23
24
|
export class BeanModelCrudInner<TRecord extends {}> extends BeanModelView<TRecord> {
|
|
@@ -66,7 +67,8 @@ export class BeanModelCrudInner<TRecord extends {}> extends BeanModelView<TRecor
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
protected async _select<
|
|
69
|
-
T extends IModelSelectParams<TRecord> | IBuildModelSelectParams<TRecord, undefined, never
|
|
70
|
+
T extends (IModelSelectParams<TRecord> | IBuildModelSelectParams<TRecord, undefined, never>) &
|
|
71
|
+
Pick<IModelSelectGeneralParams<TRecord>, 'aggrs'>,
|
|
70
72
|
>(
|
|
71
73
|
table?: keyof ITableRecord,
|
|
72
74
|
params?: T,
|
|
@@ -89,7 +91,10 @@ export class BeanModelCrudInner<TRecord extends {}> extends BeanModelView<TRecor
|
|
|
89
91
|
}
|
|
90
92
|
return `model.select: ${tip}, ${builder.toQuery()}`;
|
|
91
93
|
});
|
|
92
|
-
|
|
94
|
+
const rows = (await this.dialect.select(builder, datas, () =>
|
|
95
|
+
this.columns(table),
|
|
96
|
+
)) as TRecord[];
|
|
97
|
+
return normalizeAggregateRows(rows, params?.aggrs);
|
|
93
98
|
}
|
|
94
99
|
|
|
95
100
|
protected _select_buildParams<T extends IModelSelectGeneralParams<TRecord>>(
|
|
@@ -164,7 +169,7 @@ export class BeanModelCrudInner<TRecord extends {}> extends BeanModelView<TRecor
|
|
|
164
169
|
// ready
|
|
165
170
|
this.$loggerChild('model').debug(() => `model.count: ${builder.toQuery()}`);
|
|
166
171
|
const res = await builder;
|
|
167
|
-
return this.
|
|
172
|
+
return normalizeAggregateValue(this.extractFirstValue(res), 'count');
|
|
168
173
|
}
|
|
169
174
|
|
|
170
175
|
protected async _increment(
|
package/src/lib/dto/dto.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DtoAggregate } from './dtoAggregate.ts';
|
|
2
|
+
import { DtoAnalysisAggregate, DtoAnalysisGroup } from './dtoAnalysis.ts';
|
|
2
3
|
import { DtoCreate } from './dtoCreate.ts';
|
|
3
4
|
import { DtoGet } from './dtoGet.ts';
|
|
4
5
|
import { DtoGroup } from './dtoGroup.ts';
|
|
@@ -15,6 +16,8 @@ export const $Dto = {
|
|
|
15
16
|
mutate: DtoMutate,
|
|
16
17
|
get: DtoGet,
|
|
17
18
|
aggregate: DtoAggregate,
|
|
19
|
+
analysisGroup: DtoAnalysisGroup,
|
|
20
|
+
analysisAggregate: DtoAnalysisAggregate,
|
|
18
21
|
group: DtoGroup,
|
|
19
22
|
query: DtoQuery,
|
|
20
23
|
queryPage: DtoQueryPage,
|
|
@@ -56,7 +56,10 @@ export function _DtoAggregate_inner<
|
|
|
56
56
|
if (!columns) continue;
|
|
57
57
|
for (const column of columns) {
|
|
58
58
|
const column2 = `${key}_${column === '*' ? 'all' : column}`;
|
|
59
|
-
Api.field(v.optional(), z.string())(
|
|
59
|
+
Api.field(v.optional(), key === 'count' ? z.string() : z.string().nullable())(
|
|
60
|
+
classTarget.prototype,
|
|
61
|
+
column2,
|
|
62
|
+
);
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
return classTarget as any;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Constructable } from 'vona';
|
|
2
|
+
|
|
3
|
+
import { $Class } from 'vona';
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
IAnalysisPolicy,
|
|
7
|
+
TypeAnalysisAggregateResult,
|
|
8
|
+
TypeAnalysisGroupResult,
|
|
9
|
+
} from '../../types/analysis.ts';
|
|
10
|
+
|
|
11
|
+
import { _DtoAggregate_inner } from './dtoAggregate.ts';
|
|
12
|
+
import { DtoGroup } from './dtoGroup.ts';
|
|
13
|
+
|
|
14
|
+
/** A finite optional superset: absent fields are unrequested, null retains SQL meaning. */
|
|
15
|
+
export function DtoAnalysisGroup<Policy extends IAnalysisPolicy>(
|
|
16
|
+
policy: Policy,
|
|
17
|
+
): Constructable<TypeAnalysisGroupResult<Policy>> {
|
|
18
|
+
if (!policy.defaults.group) throw new TypeError('Analysis group action is not enabled');
|
|
19
|
+
const base = DtoGroup(policy.modelLike as any, [...policy.groups] as any, policy.aggrs as any);
|
|
20
|
+
return $Class.partial(base) as Constructable<TypeAnalysisGroupResult<Policy>>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function DtoAnalysisAggregate<Policy extends IAnalysisPolicy>(
|
|
24
|
+
policy: Policy,
|
|
25
|
+
): Constructable<TypeAnalysisAggregateResult<Policy>> {
|
|
26
|
+
if (!policy.defaults.aggregate) throw new TypeError('Analysis aggregate action is not enabled');
|
|
27
|
+
abstract class TargetClass {}
|
|
28
|
+
// Aggregate aliases deliberately do not copy field validators/renderers from source columns.
|
|
29
|
+
return _DtoAggregate_inner(
|
|
30
|
+
TargetClass as any,
|
|
31
|
+
policy.modelLike as any,
|
|
32
|
+
policy.aggrs as any,
|
|
33
|
+
) as Constructable<TypeAnalysisAggregateResult<Policy>>;
|
|
34
|
+
}
|
package/src/lib/dto/dtoCreate.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Constructable } from 'vona';
|
|
|
2
2
|
|
|
3
3
|
import { mergeTargetDecoratorDtoOpenapi } from 'vona-module-a-openapiutils';
|
|
4
4
|
|
|
5
|
-
import type { IDtoMutateParams,
|
|
5
|
+
import type { IDtoMutateParams, TypeDtoMutateClass } from '../../types/dto/dtoMutate.ts';
|
|
6
6
|
import type { IModelClassRecord } from '../../types/onion/model.ts';
|
|
7
7
|
import type { BeanModelMeta } from '../bean.model/bean.model_meta.ts';
|
|
8
8
|
|
|
@@ -16,14 +16,12 @@ export function DtoCreate<
|
|
|
16
16
|
? (() => Constructable<ModelLike>) | Constructable<ModelLike>
|
|
17
17
|
: ModelLike,
|
|
18
18
|
params?: T,
|
|
19
|
-
):
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
true
|
|
26
|
-
>
|
|
19
|
+
): TypeDtoMutateClass<
|
|
20
|
+
ModelLike,
|
|
21
|
+
T,
|
|
22
|
+
'create',
|
|
23
|
+
'id' | 'iid' | 'deleted' | 'createdAt' | 'updatedAt',
|
|
24
|
+
true
|
|
27
25
|
> {
|
|
28
26
|
const dtoClass = _DtoMutate_raw(
|
|
29
27
|
modelLike,
|
package/src/lib/dto/dtoGet.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Constructable } from 'vona';
|
|
2
2
|
|
|
3
3
|
import { ensureArray, hashkey } from '@cabloy/utils';
|
|
4
|
-
import { $Class, appResource } from 'vona';
|
|
4
|
+
import { $Class, appMetadata, appResource, registerMappedClassMetadataKey } from 'vona';
|
|
5
5
|
import {
|
|
6
6
|
addSchemaDynamic,
|
|
7
7
|
Api,
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
prepareClassModel,
|
|
25
25
|
prepareColumns,
|
|
26
26
|
} from '../../common/utils.ts';
|
|
27
|
+
import { SymbolDtoMutateRelations } from '../../types/dto/dtoMutate.ts';
|
|
27
28
|
import { handleRelationsCollection } from '../utils.ts';
|
|
28
29
|
import { DtoAggregate } from './dtoAggregate.ts';
|
|
29
30
|
import { DtoGroup } from './dtoGroup.ts';
|
|
@@ -63,10 +64,33 @@ export function _DtoGet_relations<TRecord extends {}, TModel extends BeanModelMe
|
|
|
63
64
|
includeWrapper?: IModelRelationIncludeWrapper,
|
|
64
65
|
mutateTypeTopLevel?: TypeDtoMutateType,
|
|
65
66
|
) {
|
|
66
|
-
// relations
|
|
67
67
|
const relations = _DtoGet_relations_collection(modelClass, includeWrapper);
|
|
68
|
-
|
|
68
|
+
// Mapped-class metadata follows the dtoClass field projection, including pick/omit.
|
|
69
|
+
registerMappedClassMetadataKey(entityClass.prototype, SymbolDtoMutateRelations, {});
|
|
70
|
+
const retained = appMetadata.getOwnMetadataMap<string, IRelationItem>(
|
|
71
|
+
true,
|
|
72
|
+
SymbolDtoMutateRelations,
|
|
73
|
+
entityClass.prototype,
|
|
74
|
+
);
|
|
75
|
+
if (mutateTypeTopLevel) {
|
|
76
|
+
const overridden = new Set(relations.map(relation => relation[0]));
|
|
77
|
+
for (const name in retained) {
|
|
78
|
+
if (!overridden.has(name)) {
|
|
79
|
+
_DtoGet_relation_handle(entityClass, retained[name], mutateTypeTopLevel);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
69
83
|
for (const relation of relations) {
|
|
84
|
+
const [name, definition] = relation;
|
|
85
|
+
if (
|
|
86
|
+
mutateTypeTopLevel &&
|
|
87
|
+
definition !== false &&
|
|
88
|
+
(definition.type === 'hasOne' || definition.type === 'hasMany')
|
|
89
|
+
) {
|
|
90
|
+
retained[name] = relation;
|
|
91
|
+
} else {
|
|
92
|
+
delete retained[name];
|
|
93
|
+
}
|
|
70
94
|
_DtoGet_relation_handle(entityClass, relation, mutateTypeTopLevel);
|
|
71
95
|
}
|
|
72
96
|
}
|
package/src/lib/dto/dtoMutate.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { getTargetDecoratorRuleColumns } from 'vona-module-a-openapiutils';
|
|
|
6
6
|
|
|
7
7
|
import type {
|
|
8
8
|
IDtoMutateParams,
|
|
9
|
-
|
|
9
|
+
TypeDtoMutateClass,
|
|
10
10
|
TypeDtoMutateType,
|
|
11
11
|
} from '../../types/dto/dtoMutate.ts';
|
|
12
12
|
import type { TypeModelColumnsStrict } from '../../types/modelWhere.ts';
|
|
@@ -30,7 +30,7 @@ export function DtoMutate<
|
|
|
30
30
|
? (() => Constructable<ModelLike>) | Constructable<ModelLike>
|
|
31
31
|
: ModelLike,
|
|
32
32
|
params?: T,
|
|
33
|
-
):
|
|
33
|
+
): TypeDtoMutateClass<ModelLike, T, 'mutate', undefined, true> {
|
|
34
34
|
return _DtoMutate_raw(modelLike, params, 'mutate', undefined, true, undefined);
|
|
35
35
|
}
|
|
36
36
|
|
package/src/lib/dto/dtoUpdate.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Constructable } from 'vona';
|
|
|
2
2
|
|
|
3
3
|
import { mergeTargetDecoratorDtoOpenapi } from 'vona-module-a-openapiutils';
|
|
4
4
|
|
|
5
|
-
import type { IDtoMutateParams,
|
|
5
|
+
import type { IDtoMutateParams, TypeDtoMutateClass } from '../../types/dto/dtoMutate.ts';
|
|
6
6
|
import type { IModelClassRecord } from '../../types/onion/model.ts';
|
|
7
7
|
import type { BeanModelMeta } from '../bean.model/bean.model_meta.ts';
|
|
8
8
|
|
|
@@ -16,14 +16,12 @@ export function DtoUpdate<
|
|
|
16
16
|
? (() => Constructable<ModelLike>) | Constructable<ModelLike>
|
|
17
17
|
: ModelLike,
|
|
18
18
|
params?: T,
|
|
19
|
-
):
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
true
|
|
26
|
-
>
|
|
19
|
+
): TypeDtoMutateClass<
|
|
20
|
+
ModelLike,
|
|
21
|
+
T,
|
|
22
|
+
'update',
|
|
23
|
+
'id' | 'iid' | 'deleted' | 'createdAt' | 'updatedAt',
|
|
24
|
+
true
|
|
27
25
|
> {
|
|
28
26
|
const dtoClass = _DtoMutate_raw(
|
|
29
27
|
modelLike,
|
package/src/lib/index.ts
CHANGED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { Constructable } from 'vona';
|
|
2
|
+
|
|
3
|
+
import type { BeanModelMeta } from '../lib/bean.model/bean.model_meta.ts';
|
|
4
|
+
import type { TypeModelWhere } from './modelWhere.ts';
|
|
5
|
+
import type { IModelClassRecord } from './onion/model.ts';
|
|
6
|
+
import type { TypeModelOfModelLike, TypeSymbolKeyEntity } from './relations.ts';
|
|
7
|
+
|
|
8
|
+
export type TypeAnalysisMode = 'group' | 'aggregate';
|
|
9
|
+
export type TypeAnalysisFunction = 'count' | 'sum' | 'avg' | 'min' | 'max';
|
|
10
|
+
export type TypeAnalysisModelLike =
|
|
11
|
+
| Constructable<BeanModelMeta>
|
|
12
|
+
| (() => Constructable<BeanModelMeta>)
|
|
13
|
+
| keyof IModelClassRecord;
|
|
14
|
+
export type TypeAnalysisEntity<ModelLike extends TypeAnalysisModelLike> =
|
|
15
|
+
TypeModelOfModelLike<ModelLike>[TypeSymbolKeyEntity];
|
|
16
|
+
export type TypeAnalysisField<Entity> = Extract<keyof Entity, string>;
|
|
17
|
+
export type TypeAnalysisNumericField<Entity> = Exclude<
|
|
18
|
+
{
|
|
19
|
+
[K in keyof Entity]-?: NonNullable<Entity[K]> extends number ? K : never;
|
|
20
|
+
}[keyof Entity],
|
|
21
|
+
'id' | 'iid'
|
|
22
|
+
> &
|
|
23
|
+
string;
|
|
24
|
+
|
|
25
|
+
export type TypeAnalysisAggrs = Partial<Record<TypeAnalysisFunction, readonly string[]>>;
|
|
26
|
+
export type TypeAnalysisAllowedAggrs<Entity> = {
|
|
27
|
+
readonly count?: readonly ('*' | TypeAnalysisField<Entity>)[];
|
|
28
|
+
} & {
|
|
29
|
+
readonly [
|
|
30
|
+
K in Exclude<TypeAnalysisFunction, 'count'>
|
|
31
|
+
]?: readonly TypeAnalysisNumericField<Entity>[];
|
|
32
|
+
};
|
|
33
|
+
export type TypeAnalysisSelectionAggrs<Aggrs extends TypeAnalysisAggrs> = {
|
|
34
|
+
readonly [K in keyof Aggrs]?: NonNullable<Aggrs[K]> extends readonly string[]
|
|
35
|
+
? readonly NonNullable<Aggrs[K]>[number][]
|
|
36
|
+
: never;
|
|
37
|
+
};
|
|
38
|
+
export interface IAnalysisLimits {
|
|
39
|
+
readonly maxGroups: number;
|
|
40
|
+
readonly maxMetrics: number;
|
|
41
|
+
readonly maxGroupRows: number;
|
|
42
|
+
}
|
|
43
|
+
export interface IAnalysisSelection {
|
|
44
|
+
readonly groups?: readonly string[];
|
|
45
|
+
readonly aggrs: TypeAnalysisAggrs;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Structural server-owned policy surface; model references must not be serialized. */
|
|
49
|
+
export interface IAnalysisPolicy {
|
|
50
|
+
readonly modelLike: TypeAnalysisModelLike;
|
|
51
|
+
readonly modelClass: Constructable<BeanModelMeta>;
|
|
52
|
+
readonly groups: readonly string[];
|
|
53
|
+
readonly aggrs: TypeAnalysisAggrs;
|
|
54
|
+
readonly defaults: {
|
|
55
|
+
readonly group?: IAnalysisSelection & { readonly groups: readonly string[] };
|
|
56
|
+
readonly aggregate?: { readonly aggrs: TypeAnalysisAggrs };
|
|
57
|
+
};
|
|
58
|
+
readonly limits: IAnalysisLimits;
|
|
59
|
+
}
|
|
60
|
+
export type TypeAnalysisPolicy<
|
|
61
|
+
ModelLike extends TypeAnalysisModelLike,
|
|
62
|
+
Groups extends readonly string[],
|
|
63
|
+
Aggrs extends TypeAnalysisAggrs,
|
|
64
|
+
> = Omit<IAnalysisPolicy, 'modelLike' | 'groups' | 'aggrs'> & {
|
|
65
|
+
readonly modelLike: ModelLike;
|
|
66
|
+
readonly groups: Groups;
|
|
67
|
+
readonly aggrs: Aggrs;
|
|
68
|
+
};
|
|
69
|
+
export interface IAnalysisConfig<
|
|
70
|
+
Groups extends readonly string[],
|
|
71
|
+
Aggrs extends TypeAnalysisAggrs,
|
|
72
|
+
> {
|
|
73
|
+
readonly groups: Groups;
|
|
74
|
+
readonly aggrs: Aggrs;
|
|
75
|
+
readonly defaults: {
|
|
76
|
+
readonly group?: {
|
|
77
|
+
readonly groups: readonly NoInfer<Groups[number]>[];
|
|
78
|
+
readonly aggrs: TypeAnalysisSelectionAggrs<NoInfer<Aggrs>>;
|
|
79
|
+
};
|
|
80
|
+
readonly aggregate?: { readonly aggrs: TypeAnalysisSelectionAggrs<NoInfer<Aggrs>> };
|
|
81
|
+
};
|
|
82
|
+
readonly limits?: Partial<IAnalysisLimits>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface IAnalysisParams<Policy extends IAnalysisPolicy> {
|
|
86
|
+
where?: TypeModelWhere<TypeAnalysisEntity<Policy['modelLike']>>;
|
|
87
|
+
aggrs?: TypeAnalysisSelectionAggrs<Policy['aggrs']>;
|
|
88
|
+
// Existing list controls remain accepted but never drive analysis execution.
|
|
89
|
+
columns?: unknown;
|
|
90
|
+
orders?: unknown;
|
|
91
|
+
limit?: number;
|
|
92
|
+
offset?: number;
|
|
93
|
+
pageNo?: number;
|
|
94
|
+
pageSize?: number;
|
|
95
|
+
joins?: never;
|
|
96
|
+
having?: never;
|
|
97
|
+
distinct?: never;
|
|
98
|
+
include?: never;
|
|
99
|
+
with?: never;
|
|
100
|
+
}
|
|
101
|
+
export type TypeAnalysisGroupParams<Policy extends IAnalysisPolicy> = IAnalysisParams<Policy> & {
|
|
102
|
+
groups?: readonly Policy['groups'][number][];
|
|
103
|
+
};
|
|
104
|
+
export type TypeAnalysisAggregateParams<Policy extends IAnalysisPolicy> =
|
|
105
|
+
IAnalysisParams<Policy> & {
|
|
106
|
+
groups?: never;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
type TypeAnalysisAlias<Column extends string> = Column extends '*' ? 'all' : Column;
|
|
110
|
+
export type TypeAnalysisAggregateResult<Policy extends IAnalysisPolicy> = {
|
|
111
|
+
-readonly [
|
|
112
|
+
Fn in keyof Policy['aggrs'] &
|
|
113
|
+
TypeAnalysisFunction as Policy['aggrs'][Fn] extends readonly string[]
|
|
114
|
+
? `${Fn}_${TypeAnalysisAlias<Policy['aggrs'][Fn][number]>}`
|
|
115
|
+
: never
|
|
116
|
+
]?: Fn extends 'count' ? string : string | null;
|
|
117
|
+
};
|
|
118
|
+
export type TypeAnalysisGroupResult<Policy extends IAnalysisPolicy> = Partial<
|
|
119
|
+
Pick<
|
|
120
|
+
TypeAnalysisEntity<Policy['modelLike']>,
|
|
121
|
+
Extract<Policy['groups'][number], keyof TypeAnalysisEntity<Policy['modelLike']>>
|
|
122
|
+
>
|
|
123
|
+
> &
|
|
124
|
+
TypeAnalysisAggregateResult<Policy>;
|
|
125
|
+
|
|
126
|
+
export interface IAnalysisCapabilities {
|
|
127
|
+
readonly mode: TypeAnalysisMode;
|
|
128
|
+
readonly groups: readonly string[];
|
|
129
|
+
readonly aggrs: TypeAnalysisAggrs;
|
|
130
|
+
readonly defaults: IAnalysisSelection;
|
|
131
|
+
readonly limits: IAnalysisLimits;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface IResolvedAnalysis {
|
|
135
|
+
groups?: string[];
|
|
136
|
+
aggrs: Partial<Record<TypeAnalysisFunction, string[]>>;
|
|
137
|
+
}
|
|
@@ -25,8 +25,33 @@ import type {
|
|
|
25
25
|
TypeUtilPrepareColumns,
|
|
26
26
|
} from '../relations.ts';
|
|
27
27
|
|
|
28
|
+
export const SymbolDtoMutateRelations = Symbol('SymbolDtoMutateRelations');
|
|
29
|
+
|
|
28
30
|
export type TypeDtoMutateType = 'create' | 'update' | 'mutate';
|
|
29
31
|
|
|
32
|
+
// Static phantom metadata survives ordinary subclassing without becoming a DTO field.
|
|
33
|
+
// Runtime stores the corresponding resolved relation plans as mapped-class metadata.
|
|
34
|
+
export type TypeDtoMutateClass<
|
|
35
|
+
ModelLike extends BeanModelMeta | keyof IModelClassRecord,
|
|
36
|
+
TOptionsRelation,
|
|
37
|
+
TMutateTypeTopLevel extends TypeDtoMutateType,
|
|
38
|
+
TColumnsOmitDefault extends string | string[] | undefined = undefined,
|
|
39
|
+
TTopLevel extends boolean | undefined = undefined,
|
|
40
|
+
> = Constructable<
|
|
41
|
+
TypeDtoMutateResult<
|
|
42
|
+
ModelLike,
|
|
43
|
+
TOptionsRelation,
|
|
44
|
+
TMutateTypeTopLevel,
|
|
45
|
+
TColumnsOmitDefault,
|
|
46
|
+
TTopLevel
|
|
47
|
+
>
|
|
48
|
+
> & {
|
|
49
|
+
[SymbolDtoMutateRelations]?: TypeDtoMutateOwnedRelations<
|
|
50
|
+
TypeModelOfModelLike<ModelLike>,
|
|
51
|
+
TOptionsRelation
|
|
52
|
+
>;
|
|
53
|
+
};
|
|
54
|
+
|
|
30
55
|
export type IDtoMutateParams<ModelLike extends BeanModelMeta | keyof IModelClassRecord> =
|
|
31
56
|
IBuildDtoMutateParams<
|
|
32
57
|
TypeModelOfModelLike<ModelLike>[TypeSymbolKeyEntity],
|
|
@@ -65,100 +90,112 @@ export type TypeDtoMutateRelationResult<
|
|
|
65
90
|
TTopLevel extends boolean | undefined = undefined,
|
|
66
91
|
TColumns = undefined,
|
|
67
92
|
REFKEY = undefined,
|
|
68
|
-
> =
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
TColumnsOmitDefault,
|
|
75
|
-
TTopLevel,
|
|
76
|
-
REFKEY
|
|
77
|
-
>) &
|
|
78
|
-
(TModel extends BeanModelMeta
|
|
79
|
-
? OmitNever<
|
|
80
|
-
TypeDtoMutateRelationResultMergeInclude<
|
|
81
|
-
TMutateTypeTopLevel,
|
|
82
|
-
TypeUtilGetModelOptions<TModel>,
|
|
83
|
-
TypeUtilGetParamsInlcude<TOptionsRelation>
|
|
84
|
-
>
|
|
85
|
-
> &
|
|
86
|
-
OmitNever<
|
|
87
|
-
TypeDtoMutateModelRelationResultMergeWith<
|
|
88
|
-
TMutateTypeTopLevel,
|
|
89
|
-
TypeUtilGetParamsWith<TOptionsRelation>
|
|
90
|
-
>
|
|
91
|
-
>
|
|
92
|
-
: {});
|
|
93
|
-
|
|
94
|
-
type TypeDtoMutateRelationResultMergeInclude<
|
|
95
|
-
TMutateTypeTopLevel extends TypeDtoMutateType,
|
|
96
|
-
TModelOptions extends IDecoratorModelOptions,
|
|
97
|
-
TInclude extends {} | undefined | unknown,
|
|
98
|
-
> = {
|
|
99
|
-
[RelationName in keyof TModelOptions['relations']]: TInclude extends {}
|
|
100
|
-
? TInclude[RelationName] extends {} | boolean
|
|
101
|
-
? TypeDtoMutateRelationResultMergeIncludeWrapper<
|
|
102
|
-
TMutateTypeTopLevel,
|
|
103
|
-
TModelOptions['relations'][RelationName],
|
|
104
|
-
TInclude[RelationName]
|
|
105
|
-
>
|
|
106
|
-
: TypeDtoMutateRelationResultMergeAutoload<
|
|
107
|
-
TMutateTypeTopLevel,
|
|
108
|
-
TModelOptions['relations'][RelationName]
|
|
109
|
-
>
|
|
110
|
-
: TypeDtoMutateRelationResultMergeAutoload<
|
|
93
|
+
> = TypeDtoMutateMergeRelations<
|
|
94
|
+
TOptionsRelation extends { dtoClass: Constructable<infer TDto> }
|
|
95
|
+
? TypeDtoMutateRelationResultDto<TDto, TMutateTypeTopLevel, TTopLevel, REFKEY>
|
|
96
|
+
: TypeDtoMutateRelationResultEntity<
|
|
97
|
+
TRecord,
|
|
98
|
+
TColumns extends string | string[] ? TColumns : TypeUtilGetParamsColumns<TOptionsRelation>,
|
|
111
99
|
TMutateTypeTopLevel,
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
100
|
+
TColumnsOmitDefault,
|
|
101
|
+
TTopLevel,
|
|
102
|
+
REFKEY
|
|
103
|
+
>,
|
|
104
|
+
TypeDtoMutateRelationPlans<TModel, TOptionsRelation>,
|
|
105
|
+
TMutateTypeTopLevel
|
|
106
|
+
>;
|
|
115
107
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
108
|
+
// Plans describe only declared relations, never arbitrary object/array schema fields.
|
|
109
|
+
// A fresh include/with/autoload selection replaces the whole retained plan of that name.
|
|
110
|
+
type TypeDtoMutateIncludePlans<TModelOptions extends IDecoratorModelOptions, TInclude> = OmitNever<{
|
|
111
|
+
[Name in keyof TModelOptions['relations']]: TInclude extends {}
|
|
112
|
+
? TInclude[Name] extends false
|
|
113
|
+
? false
|
|
114
|
+
: TInclude[Name] extends true
|
|
115
|
+
? [TModelOptions['relations'][Name], undefined]
|
|
116
|
+
: TInclude[Name] extends {}
|
|
117
|
+
? [TModelOptions['relations'][Name], TInclude[Name]]
|
|
118
|
+
: TypeDtoMutateAutoloadPlan<TModelOptions['relations'][Name]>
|
|
119
|
+
: TypeDtoMutateAutoloadPlan<TModelOptions['relations'][Name]>;
|
|
120
|
+
}>;
|
|
121
|
+
|
|
122
|
+
type TypeDtoMutateAutoloadPlan<Relation> =
|
|
123
|
+
TypeUtilGetRelationOptionsAutoload<Relation> extends true ? [Relation, undefined] : never;
|
|
124
|
+
|
|
125
|
+
type TypeDtoMutateWithPlans<TWith> = TWith extends {}
|
|
126
|
+
? OmitNever<{
|
|
127
|
+
[Name in keyof TWith]: TWith[Name] extends boolean
|
|
128
|
+
? never
|
|
129
|
+
: TWith[Name] extends {}
|
|
130
|
+
? [TWith[Name], TypeUtilGetRelationOptions<TWith[Name]>]
|
|
131
|
+
: never;
|
|
132
|
+
}>
|
|
126
133
|
: {};
|
|
127
134
|
|
|
128
|
-
type
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
> =
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
type TypeDtoMutateFreshPlans<
|
|
136
|
+
TModel extends BeanModelMeta | undefined,
|
|
137
|
+
TOptionsRelation,
|
|
138
|
+
TWith = TypeDtoMutateWithPlans<TypeUtilGetParamsWith<TOptionsRelation>>,
|
|
139
|
+
> = Omit<
|
|
140
|
+
TModel extends BeanModelMeta
|
|
141
|
+
? TypeDtoMutateIncludePlans<
|
|
142
|
+
TypeUtilGetModelOptions<TModel>,
|
|
143
|
+
TypeUtilGetParamsInlcude<TOptionsRelation>
|
|
144
|
+
>
|
|
145
|
+
: {},
|
|
146
|
+
keyof TWith
|
|
147
|
+
> &
|
|
148
|
+
TWith;
|
|
139
149
|
|
|
140
|
-
type
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
150
|
+
type TypeDtoMutateRetainedPlans<TOptionsRelation> = TOptionsRelation extends {
|
|
151
|
+
dtoClass: infer TClass extends Constructable<unknown>;
|
|
152
|
+
}
|
|
153
|
+
? typeof SymbolDtoMutateRelations extends keyof TClass
|
|
154
|
+
? Pick<
|
|
155
|
+
NonNullable<TClass[typeof SymbolDtoMutateRelations]>,
|
|
156
|
+
Extract<
|
|
157
|
+
keyof NonNullable<TClass[typeof SymbolDtoMutateRelations]>,
|
|
158
|
+
keyof InstanceType<TClass>
|
|
159
|
+
>
|
|
160
|
+
>
|
|
161
|
+
: {}
|
|
162
|
+
: {};
|
|
163
|
+
|
|
164
|
+
type TypeDtoMutateRelationPlans<
|
|
165
|
+
TModel extends BeanModelMeta | undefined,
|
|
166
|
+
TOptionsRelation,
|
|
167
|
+
TFresh = TypeDtoMutateFreshPlans<TModel, TOptionsRelation>,
|
|
168
|
+
> = Omit<TypeDtoMutateRetainedPlans<TOptionsRelation>, keyof TFresh> & TFresh;
|
|
169
|
+
|
|
170
|
+
type TypeDtoMutateOwnedRelations<
|
|
171
|
+
TModel extends BeanModelMeta | undefined,
|
|
172
|
+
TOptionsRelation,
|
|
173
|
+
TPlans = TypeDtoMutateRelationPlans<TModel, TOptionsRelation>,
|
|
174
|
+
> = OmitNever<{
|
|
175
|
+
[Name in keyof TPlans]: TPlans[Name] extends [infer Relation, unknown]
|
|
176
|
+
? TypeUtilGetRelationType<Relation> extends 'hasOne' | 'hasMany'
|
|
177
|
+
? TPlans[Name]
|
|
178
|
+
: never
|
|
146
179
|
: never;
|
|
180
|
+
}>;
|
|
147
181
|
|
|
148
|
-
type
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
182
|
+
type TypeDtoMutateProjectRelations<TPlans, TMutateType extends TypeDtoMutateType> = OmitNever<{
|
|
183
|
+
[Name in keyof TPlans]: TPlans[Name] extends [infer Relation, infer IncludeWrapper]
|
|
184
|
+
? TypeUtilGetDtoMutateRelationEntityByType<TMutateType, Relation, IncludeWrapper>
|
|
185
|
+
: never;
|
|
186
|
+
}>;
|
|
187
|
+
|
|
188
|
+
type TypeDtoMutateDisabledRelations<TPlans> = {
|
|
189
|
+
[Name in keyof TPlans]: TPlans[Name] extends false ? Name : never;
|
|
190
|
+
}[keyof TPlans];
|
|
191
|
+
|
|
192
|
+
type TypeDtoMutateMergeRelations<
|
|
193
|
+
TBase,
|
|
194
|
+
TPlans,
|
|
195
|
+
TMutateType extends TypeDtoMutateType,
|
|
196
|
+
TRelations = TypeDtoMutateProjectRelations<TPlans, TMutateType>,
|
|
197
|
+
TDisabled extends keyof TBase = Extract<keyof TBase, TypeDtoMutateDisabledRelations<TPlans>>,
|
|
198
|
+
> = Omit<TBase, keyof TRelations | TDisabled> & Partial<Pick<TBase, TDisabled>> & TRelations;
|
|
162
199
|
|
|
163
200
|
// Relation options supply the default dtoClass; an include wrapper may override it.
|
|
164
201
|
type TypeUtilGetDtoMutateRelationParams<Relation, IncludeWrapper> = IncludeWrapper extends {
|
package/src/types/index.ts
CHANGED
|
@@ -27,7 +27,7 @@ export type TypeUtilAggrPrepareColumns<TColumns> = TColumns extends string[]
|
|
|
27
27
|
: undefined;
|
|
28
28
|
export type TypeRecordAggrsValues<TRecord extends Record<string, any>> = TRecord[keyof TRecord];
|
|
29
29
|
export type TypeRecordAggrsValuesToObject<AggrValues extends string> = {
|
|
30
|
-
[K in AggrValues]: string | undefined;
|
|
30
|
+
[K in AggrValues]: K extends `count_${string}` ? string | undefined : string | null | undefined;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
export type TypeUtilGetAggrsFromRelationAndIncludeWrapper<
|