@solidxai/core 0.1.4 → 0.1.5-beta.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/.claude/settings.local.json +8 -0
- package/dist/constants/error-messages.d.ts +1 -0
- package/dist/constants/error-messages.d.ts.map +1 -1
- package/dist/constants/error-messages.js +1 -0
- package/dist/constants/error-messages.js.map +1 -1
- package/dist/constants.d.ts +3 -3
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +12 -12
- package/dist/constants.js.map +1 -1
- package/dist/controllers/otp-authentication.controller.d.ts +1 -4
- package/dist/controllers/otp-authentication.controller.d.ts.map +1 -1
- package/dist/controllers/otp-authentication.controller.js +1 -1
- package/dist/controllers/role-metadata.controller.d.ts +1 -0
- package/dist/controllers/role-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/role-metadata.controller.js +15 -0
- package/dist/controllers/role-metadata.controller.js.map +1 -1
- package/dist/dtos/create-email-template.dto.d.ts.map +1 -1
- package/dist/dtos/create-email-template.dto.js.map +1 -1
- package/dist/dtos/create-list-of-values.dto.d.ts.map +1 -1
- package/dist/dtos/create-list-of-values.dto.js.map +1 -1
- package/dist/dtos/create-menu-item-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-menu-item-metadata.dto.js.map +1 -1
- package/dist/dtos/create-role-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-role-metadata.dto.js.map +1 -1
- package/dist/dtos/create-scheduled-job.dto.d.ts.map +1 -1
- package/dist/dtos/create-scheduled-job.dto.js.map +1 -1
- package/dist/dtos/create-security-rule.dto.d.ts.map +1 -1
- package/dist/dtos/create-security-rule.dto.js.map +1 -1
- package/dist/dtos/create-sms-template.dto.d.ts.map +1 -1
- package/dist/dtos/create-sms-template.dto.js.map +1 -1
- package/dist/dtos/create-view-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-view-metadata.dto.js.map +1 -1
- package/dist/dtos/otp-sign-in.dto.d.ts +1 -1
- package/dist/dtos/otp-sign-in.dto.d.ts.map +1 -1
- package/dist/dtos/otp-sign-in.dto.js +2 -2
- package/dist/dtos/otp-sign-in.dto.js.map +1 -1
- package/dist/dtos/otp-sign-up.dto.d.ts +2 -2
- package/dist/dtos/otp-sign-up.dto.d.ts.map +1 -1
- package/dist/dtos/otp-sign-up.dto.js +2 -2
- package/dist/dtos/otp-sign-up.dto.js.map +1 -1
- package/dist/dtos/resolve-s3-url.dto.d.ts +2 -5
- package/dist/dtos/resolve-s3-url.dto.d.ts.map +1 -1
- package/dist/dtos/resolve-s3-url.dto.js +1 -13
- package/dist/dtos/resolve-s3-url.dto.js.map +1 -1
- package/dist/dtos/sign-up.dto.d.ts.map +1 -1
- package/dist/dtos/sign-up.dto.js.map +1 -1
- package/dist/dtos/update-email-template.dto.d.ts.map +1 -1
- package/dist/dtos/update-email-template.dto.js.map +1 -1
- package/dist/dtos/update-list-of-values.dto.d.ts.map +1 -1
- package/dist/dtos/update-list-of-values.dto.js.map +1 -1
- package/dist/dtos/update-menu-item-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/update-menu-item-metadata.dto.js.map +1 -1
- package/dist/dtos/update-scheduled-job.dto.d.ts.map +1 -1
- package/dist/dtos/update-scheduled-job.dto.js.map +1 -1
- package/dist/dtos/update-security-rule.dto.d.ts.map +1 -1
- package/dist/dtos/update-security-rule.dto.js.map +1 -1
- package/dist/dtos/update-sms-template.dto.d.ts.map +1 -1
- package/dist/dtos/update-sms-template.dto.js.map +1 -1
- package/dist/dtos/update-view-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/update-view-metadata.dto.js.map +1 -1
- package/dist/entities/user.entity.d.ts +1 -0
- package/dist/entities/user.entity.d.ts.map +1 -1
- package/dist/entities/user.entity.js +6 -1
- package/dist/entities/user.entity.js.map +1 -1
- package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.d.ts +2 -0
- package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.js +33 -23
- package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.js.map +1 -1
- package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.d.ts +3 -0
- package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.js +36 -23
- package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.js.map +1 -1
- package/dist/helpers/security.helper.js +1 -0
- package/dist/helpers/security.helper.js.map +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -4
- package/dist/index.js.map +1 -1
- package/dist/repository/solid-base.repository.d.ts +10 -1
- package/dist/repository/solid-base.repository.d.ts.map +1 -1
- package/dist/repository/solid-base.repository.js +109 -0
- package/dist/repository/solid-base.repository.js.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts +2 -0
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +141 -71
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/permission-metadata-seeder.service.d.ts +1 -1
- package/dist/seeders/permission-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/permission-metadata-seeder.service.js +1 -1
- package/dist/seeders/permission-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +12 -25
- package/dist/services/authentication.service.d.ts +22 -8
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +228 -214
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/crud-helper.service.d.ts +4 -0
- package/dist/services/crud-helper.service.d.ts.map +1 -1
- package/dist/services/crud-helper.service.js +66 -32
- package/dist/services/crud-helper.service.js.map +1 -1
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +7 -4
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/field-metadata.service.d.ts.map +1 -1
- package/dist/services/field-metadata.service.js.map +1 -1
- package/dist/services/file/disk-file.service.d.ts +0 -2
- package/dist/services/file/disk-file.service.d.ts.map +1 -1
- package/dist/services/file/disk-file.service.js +7 -16
- package/dist/services/file/disk-file.service.js.map +1 -1
- package/dist/services/file/index.d.ts +1 -0
- package/dist/services/file/index.d.ts.map +1 -1
- package/dist/services/file/index.js +1 -0
- package/dist/services/file/index.js.map +1 -1
- package/dist/services/file/storage-path-builder.d.ts +17 -0
- package/dist/services/file/storage-path-builder.d.ts.map +1 -0
- package/dist/{seeders/sms-template-seeder.service.js → services/file/storage-path-builder.js} +45 -35
- package/dist/services/file/storage-path-builder.js.map +1 -0
- package/dist/services/media.service.d.ts +1 -1
- package/dist/services/media.service.d.ts.map +1 -1
- package/dist/services/media.service.js +45 -6
- package/dist/services/media.service.js.map +1 -1
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
- package/dist/services/mediaStorageProviders/file-storage-provider.d.ts.map +1 -1
- package/dist/services/mediaStorageProviders/file-storage-provider.js +46 -7
- package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
- package/dist/services/module-metadata.service.d.ts +4 -6
- package/dist/services/module-metadata.service.d.ts.map +1 -1
- package/dist/services/module-metadata.service.js +16 -14
- package/dist/services/module-metadata.service.js.map +1 -1
- package/dist/services/setting.service.d.ts +3 -2
- package/dist/services/setting.service.d.ts.map +1 -1
- package/dist/services/setting.service.js +7 -4
- package/dist/services/setting.service.js.map +1 -1
- package/dist/services/settings/default-settings-provider.service.d.ts +24 -2
- package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
- package/dist/services/settings/default-settings-provider.service.js +8 -6
- package/dist/services/settings/default-settings-provider.service.js.map +1 -1
- package/dist/solid-core.module.d.ts +3 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +45 -9
- package/dist/solid-core.module.js.map +1 -1
- package/dist/testing/adapters/ui/playwright-adapter.d.ts.map +1 -1
- package/dist/testing/adapters/ui/playwright-adapter.js +35 -2
- package/dist/testing/adapters/ui/playwright-adapter.js.map +1 -1
- package/package.json +8 -2
- package/src/constants/error-messages.ts +1 -0
- package/src/constants.ts +3 -3
- package/src/controllers/role-metadata.controller.ts +26 -18
- package/src/dtos/create-email-template.dto.ts +7 -0
- package/src/dtos/create-list-of-values.dto.ts +7 -0
- package/src/dtos/create-menu-item-metadata.dto.ts +12 -1
- package/src/dtos/create-role-metadata.dto.ts +9 -0
- package/src/dtos/create-scheduled-job.dto.ts +14 -0
- package/src/dtos/create-security-rule.dto.ts +6 -0
- package/src/dtos/create-sms-template.dto.ts +6 -0
- package/src/dtos/create-view-metadata.dto.ts +11 -0
- package/src/dtos/otp-sign-in.dto.ts +3 -3
- package/src/dtos/otp-sign-up.dto.ts +3 -3
- package/src/dtos/resolve-s3-url.dto.ts +2 -12
- package/src/dtos/sign-up.dto.ts +0 -2
- package/src/dtos/update-email-template.dto.ts +6 -0
- package/src/dtos/update-list-of-values.dto.ts +8 -0
- package/src/dtos/update-menu-item-metadata.dto.ts +12 -0
- package/src/dtos/update-scheduled-job.dto.ts +15 -0
- package/src/dtos/update-security-rule.dto.ts +7 -0
- package/src/dtos/update-sms-template.dto.ts +32 -32
- package/src/dtos/update-view-metadata.dto.ts +12 -0
- package/src/entities/user.entity.ts +3 -0
- package/src/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.ts +43 -32
- package/src/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.ts +45 -33
- package/src/helpers/security.helper.ts +1 -1
- package/src/index.ts +0 -4
- package/src/repository/solid-base.repository.ts +172 -1
- package/src/seeders/module-metadata-seeder.service.ts +188 -126
- package/src/seeders/permission-metadata-seeder.service.ts +1 -4
- package/src/seeders/seed-data/solid-core-metadata.json +12 -25
- package/src/services/authentication.service.ts +268 -266
- package/src/services/crud-helper.service.ts +79 -36
- package/src/services/crud.service.ts +9 -4
- package/src/services/field-metadata.service.ts +0 -71
- package/src/services/file/disk-file.service.ts +8 -18
- package/src/services/file/index.ts +1 -0
- package/src/services/file/storage-path-builder.ts +56 -0
- package/src/services/media.service.ts +13 -7
- package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +1 -1
- package/src/services/mediaStorageProviders/file-storage-provider.ts +13 -8
- package/src/services/module-metadata.service.ts +18 -15
- package/src/services/setting.service.ts +5 -3
- package/src/services/settings/default-settings-provider.service.ts +5 -3
- package/src/solid-core.module.ts +16 -12
- package/src/testing/adapters/ui/playwright-adapter.ts +1 -1
- package/dist/passport-strategies/local.strategy.d.ts +0 -15
- package/dist/passport-strategies/local.strategy.d.ts.map +0 -1
- package/dist/passport-strategies/local.strategy.js +0 -44
- package/dist/passport-strategies/local.strategy.js.map +0 -1
- package/dist/seeders/email-template-seeder.service.d.ts +0 -10
- package/dist/seeders/email-template-seeder.service.d.ts.map +0 -1
- package/dist/seeders/email-template-seeder.service.js +0 -84
- package/dist/seeders/email-template-seeder.service.js.map +0 -1
- package/dist/seeders/sms-template-seeder.service.d.ts +0 -10
- package/dist/seeders/sms-template-seeder.service.d.ts.map +0 -1
- package/dist/seeders/sms-template-seeder.service.js.map +0 -1
- package/dist/seeders/user-seeder.service.d.ts +0 -10
- package/dist/seeders/user-seeder.service.d.ts.map +0 -1
- package/dist/seeders/user-seeder.service.js +0 -44
- package/dist/seeders/user-seeder.service.js.map +0 -1
- package/src/passport-strategies/local.strategy.ts +0 -28
- package/src/seeders/email-template-seeder.service.ts +0 -49
- package/src/seeders/sms-template-seeder.service.ts +0 -50
- package/src/seeders/user-seeder.service.ts +0 -33
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { classify } from "@angular-devkit/core/src/utils/strings";
|
|
2
|
+
import { Logger } from "@nestjs/common";
|
|
2
3
|
import { isEmpty, isEnum, isInt, isNotEmpty } from "class-validator";
|
|
3
4
|
import { RelationFieldsCommand } from "src/dtos/create-field-metadata.dto";
|
|
4
|
-
import { FieldMetadata } from "src/entities/field-metadata.entity";
|
|
5
5
|
import { FieldCrudManager, ValidationError } from "src/interfaces";
|
|
6
6
|
import { EntityManager, In } from "typeorm";
|
|
7
7
|
|
|
@@ -13,12 +13,15 @@ export interface OneToManyRelationFieldOptions {
|
|
|
13
13
|
modelSingularName: string | undefined | null;
|
|
14
14
|
inverseFieldName: string | undefined | null;
|
|
15
15
|
entityManager: EntityManager | undefined | null;
|
|
16
|
+
isUpdate?: boolean;
|
|
17
|
+
entityId?: number;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
const linkCommands = [RelationFieldsCommand.link, RelationFieldsCommand.unlink, RelationFieldsCommand.set];
|
|
19
21
|
|
|
20
22
|
// This implementation is meant to be used for many-to-one relation field
|
|
21
23
|
export class OneToManyRelationFieldCrudManager implements FieldCrudManager {
|
|
24
|
+
private readonly logger = new Logger(OneToManyRelationFieldCrudManager.name);
|
|
22
25
|
|
|
23
26
|
private readonly valueFieldName: string;
|
|
24
27
|
private readonly idFieldName: string;
|
|
@@ -74,18 +77,22 @@ export class OneToManyRelationFieldCrudManager implements FieldCrudManager {
|
|
|
74
77
|
}
|
|
75
78
|
|
|
76
79
|
async transformForCreate(dto: any): Promise<any> {
|
|
77
|
-
// const relatedFieldData: any[] = dto[this.fieldName()];
|
|
78
80
|
const currentEntityName = classify(this.options.modelSingularName);
|
|
79
81
|
const currentEntityRepository = this.options.entityManager.getRepository(currentEntityName);
|
|
80
82
|
|
|
81
83
|
const relatedEntityName = classify(this.options.relationCoModelSingularName);
|
|
82
84
|
const relatedEntityRepository = this.options.entityManager.getRepository(relatedEntityName);
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
const result = await this.transformByCommand(dto, relatedEntityRepository, currentEntityRepository);
|
|
87
|
+
if (result !== undefined) {
|
|
88
|
+
dto[this.valueFieldName] = result;
|
|
89
|
+
} else {
|
|
90
|
+
delete dto[this.valueFieldName];
|
|
91
|
+
}
|
|
85
92
|
return dto;
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
private async transformByCommand(dto: any, relatedEntityRepository: any, currentEntityRepository: any): Promise<any[]> {
|
|
95
|
+
private async transformByCommand(dto: any, relatedEntityRepository: any, currentEntityRepository: any): Promise<any[] | undefined> {
|
|
89
96
|
// TODO : Need to add support for the multiple commands
|
|
90
97
|
const command = dto[this.commandFieldName];
|
|
91
98
|
const values = dto[this.valueFieldName];
|
|
@@ -101,13 +108,14 @@ export class OneToManyRelationFieldCrudManager implements FieldCrudManager {
|
|
|
101
108
|
case RelationFieldsCommand.clear:
|
|
102
109
|
return this.transformForCommandClear();
|
|
103
110
|
case RelationFieldsCommand.set:
|
|
104
|
-
return await this.transformForCommandSet(ids, relatedEntityRepository
|
|
111
|
+
return await this.transformForCommandSet(ids, relatedEntityRepository);
|
|
105
112
|
case RelationFieldsCommand.link:
|
|
106
|
-
return await this.tranformForCommandLink(ids, relatedEntityRepository
|
|
113
|
+
return await this.tranformForCommandLink(ids, relatedEntityRepository);
|
|
107
114
|
case RelationFieldsCommand.unlink:
|
|
108
|
-
return await this.transformForCommandUnLink(ids
|
|
115
|
+
return await this.transformForCommandUnLink(ids);
|
|
109
116
|
default:
|
|
110
|
-
|
|
117
|
+
this.logger.log(`Invalid command ${command}`);
|
|
118
|
+
return null;
|
|
111
119
|
}
|
|
112
120
|
}
|
|
113
121
|
|
|
@@ -115,46 +123,50 @@ export class OneToManyRelationFieldCrudManager implements FieldCrudManager {
|
|
|
115
123
|
return []
|
|
116
124
|
}
|
|
117
125
|
|
|
118
|
-
private async transformForCommandSet(ids: any[], relatedEntityRepository: any
|
|
119
|
-
// Load the entities with the ids passed
|
|
126
|
+
private async transformForCommandSet(ids: any[], relatedEntityRepository: any): Promise<any[]> {
|
|
120
127
|
const loadedEntities: any[] = await relatedEntityRepository.find({
|
|
121
|
-
where : {id: In(ids) }
|
|
128
|
+
where : {id: In(ids) }
|
|
122
129
|
})
|
|
123
130
|
if (loadedEntities.length !== ids.length) {
|
|
124
|
-
throw new Error('Invalid entity ids provided for
|
|
131
|
+
throw new Error('Invalid entity ids provided for set');
|
|
125
132
|
}
|
|
126
133
|
|
|
127
134
|
return loadedEntities;
|
|
128
135
|
}
|
|
129
136
|
|
|
130
|
-
private async tranformForCommandLink(ids: any, relatedEntityRepository: any
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
+
private async tranformForCommandLink(ids: any[], relatedEntityRepository: any): Promise<undefined> {
|
|
138
|
+
if (!this.options.isUpdate) {
|
|
139
|
+
throw new Error('Link command is only supported for update operations');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const count: number = await relatedEntityRepository.count({
|
|
143
|
+
where: { id: In(ids) }
|
|
144
|
+
});
|
|
145
|
+
if (count !== ids.length) {
|
|
137
146
|
throw new Error('Invalid entity ids provided for linking');
|
|
138
147
|
}
|
|
139
|
-
tranformedRelatedFields.push(...loadedEntities);
|
|
140
148
|
|
|
141
|
-
|
|
149
|
+
await this.options.entityManager
|
|
150
|
+
.createQueryBuilder()
|
|
151
|
+
.relation(classify(this.options.modelSingularName), this.valueFieldName)
|
|
152
|
+
.of(this.options.entityId)
|
|
153
|
+
.add(ids);
|
|
154
|
+
|
|
155
|
+
return undefined;
|
|
142
156
|
}
|
|
143
157
|
|
|
144
|
-
private async transformForCommandUnLink(ids: any
|
|
145
|
-
if (
|
|
146
|
-
throw new Error('
|
|
147
|
-
}
|
|
158
|
+
private async transformForCommandUnLink(ids: any[]): Promise<undefined> {
|
|
159
|
+
if (!this.options.isUpdate) {
|
|
160
|
+
throw new Error('Unlink command is only supported for update operations');
|
|
161
|
+
}
|
|
148
162
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const filteredEntities = entityInstance[this.valueFieldName].filter((entity) => !ids.includes(entity.id));
|
|
155
|
-
tranformedRelatedFields.push(...filteredEntities);
|
|
163
|
+
await this.options.entityManager
|
|
164
|
+
.createQueryBuilder()
|
|
165
|
+
.relation(classify(this.options.modelSingularName), this.valueFieldName)
|
|
166
|
+
.of(this.options.entityId)
|
|
167
|
+
.remove(ids);
|
|
156
168
|
|
|
157
|
-
return
|
|
169
|
+
return undefined;
|
|
158
170
|
}
|
|
159
171
|
|
|
160
172
|
private async transformForCommandCreate(values: any[], relatedEntityRepository: any): Promise<any[]> {
|
|
@@ -24,7 +24,7 @@ export function buildDefaultSecurityHeaderOptions(): Readonly<HelmetOptions> {
|
|
|
24
24
|
|
|
25
25
|
// clickjacking defense (modern)
|
|
26
26
|
"frame-ancestors": ["'none'"],
|
|
27
|
-
|
|
27
|
+
"style-src": ["'self'"],
|
|
28
28
|
// add/adjust as needed for your app:
|
|
29
29
|
// "script-src": ["'self'"], // add hashes/nonces/CSPRO if needed
|
|
30
30
|
// "style-src": ["'self'", "'unsafe-inline'"],
|
package/src/index.ts
CHANGED
|
@@ -212,16 +212,12 @@ export * from './jobs/msg91-whatsapp-subscriber.service'
|
|
|
212
212
|
export * from './listeners/user-registration.listener'
|
|
213
213
|
|
|
214
214
|
export * from './passport-strategies/google-oauth.strategy'
|
|
215
|
-
export * from './passport-strategies/local.strategy'
|
|
216
215
|
|
|
217
216
|
export * from './services/selection-providers/list-of-values-selection-providers.service'
|
|
218
217
|
|
|
219
218
|
// seed-data
|
|
220
|
-
export * from './seeders/email-template-seeder.service'
|
|
221
219
|
export * from './seeders/permission-metadata-seeder.service'
|
|
222
|
-
export * from './seeders/sms-template-seeder.service'
|
|
223
220
|
export * from './seeders/module-metadata-seeder.service'
|
|
224
|
-
export * from './seeders/user-seeder.service'
|
|
225
221
|
|
|
226
222
|
// export * from './services/access-token-storage.service'
|
|
227
223
|
export * from './services/action-metadata.service'
|
|
@@ -13,9 +13,11 @@ import {
|
|
|
13
13
|
FindOptionsWhere,
|
|
14
14
|
QueryRunner,
|
|
15
15
|
Repository,
|
|
16
|
-
SelectQueryBuilder
|
|
16
|
+
SelectQueryBuilder,
|
|
17
|
+
UpdateResult
|
|
17
18
|
} from 'typeorm';
|
|
18
19
|
import { SecurityRuleRepository } from './security-rule.repository';
|
|
20
|
+
import { PickKeysByType } from 'typeorm/common/PickKeysByType';
|
|
19
21
|
|
|
20
22
|
export class SolidBaseRepository<T extends CommonEntity> extends Repository<T> {
|
|
21
23
|
protected readonly logger: Logger;
|
|
@@ -132,4 +134,173 @@ export class SolidBaseRepository<T extends CommonEntity> extends Repository<T> {
|
|
|
132
134
|
|
|
133
135
|
return qb.getManyAndCount();
|
|
134
136
|
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Security-aware count(): applies security rules before counting.
|
|
140
|
+
*/
|
|
141
|
+
override async count(options?: FindManyOptions<T>): Promise<number> {
|
|
142
|
+
const alias = this.modelSingularName();
|
|
143
|
+
const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
|
|
144
|
+
|
|
145
|
+
if (options) {
|
|
146
|
+
qb.setFindOptions(options);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return qb.getCount();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Security-aware countBy(): convenience wrapper routed through count().
|
|
154
|
+
*/
|
|
155
|
+
override async countBy(where: FindOptionsWhere<T> | FindOptionsWhere<T>[]): Promise<number> {
|
|
156
|
+
return this.count({ where });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Security-aware average(): applies security rules before computing the average.
|
|
161
|
+
*/
|
|
162
|
+
override async average(columnName: PickKeysByType<T, number>, where?: FindOptionsWhere<T> | FindOptionsWhere<T>[]): Promise<number | null> {
|
|
163
|
+
const alias = this.modelSingularName();
|
|
164
|
+
const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
|
|
165
|
+
|
|
166
|
+
if (where) {
|
|
167
|
+
qb.setFindOptions({ where });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const result = await qb
|
|
171
|
+
.select(`AVG(CAST(${alias}.${String(columnName)} AS FLOAT))`, 'avg')
|
|
172
|
+
.getRawOne<{ avg: string | number | null }>();
|
|
173
|
+
|
|
174
|
+
if (result?.avg === null || result?.avg === undefined) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return typeof result.avg === 'number'
|
|
179
|
+
? result.avg
|
|
180
|
+
: parseFloat(result.avg);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Security-aware sum(): applies security rules before computing the sum.
|
|
185
|
+
*/
|
|
186
|
+
override async sum(columnName: PickKeysByType<T, number>, where?: FindOptionsWhere<T> | FindOptionsWhere<T>[]): Promise<number | null> {
|
|
187
|
+
const alias = this.modelSingularName();
|
|
188
|
+
const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
|
|
189
|
+
|
|
190
|
+
if (where) {
|
|
191
|
+
qb.setFindOptions({ where });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const result = await qb
|
|
195
|
+
.select(`SUM(CAST(${alias}.${String(columnName)} AS FLOAT))`, 'sum')
|
|
196
|
+
.getRawOne<{ sum: string | number | null }>();
|
|
197
|
+
|
|
198
|
+
if (result?.sum === null || result?.sum === undefined) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return typeof result.sum === 'number'
|
|
203
|
+
? result.sum
|
|
204
|
+
: parseFloat(result.sum);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Security-aware minimum(): applies security rules before computing the minimum.
|
|
209
|
+
*/
|
|
210
|
+
override async minimum(columnName: PickKeysByType<T, number>, where?: FindOptionsWhere<T> | FindOptionsWhere<T>[]): Promise<number | null> {
|
|
211
|
+
const alias = this.modelSingularName();
|
|
212
|
+
const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
|
|
213
|
+
|
|
214
|
+
if (where) {
|
|
215
|
+
qb.setFindOptions({ where });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const result = await qb
|
|
219
|
+
.select(`MIN(CAST(${alias}.${String(columnName)} AS FLOAT))`, 'min')
|
|
220
|
+
.getRawOne<{ min: string | number | null }>();
|
|
221
|
+
|
|
222
|
+
if (result?.min === null || result?.min === undefined) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return typeof result.min === 'number'
|
|
227
|
+
? result.min
|
|
228
|
+
: parseFloat(result.min);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Security-aware maximum(): applies security rules before computing the maximum.
|
|
233
|
+
*/
|
|
234
|
+
override async maximum(columnName: PickKeysByType<T, number>, where?: FindOptionsWhere<T> | FindOptionsWhere<T>[]): Promise<number | null> {
|
|
235
|
+
const alias = this.modelSingularName();
|
|
236
|
+
const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
|
|
237
|
+
|
|
238
|
+
if (where) {
|
|
239
|
+
qb.setFindOptions({ where });
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const result = await qb
|
|
243
|
+
.select(`MAX(CAST(${alias}.${String(columnName)} AS FLOAT))`, 'max')
|
|
244
|
+
.getRawOne<{ max: string | number | null }>();
|
|
245
|
+
|
|
246
|
+
if (result?.max === null || result?.max === undefined) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return typeof result.max === 'number'
|
|
251
|
+
? result.max
|
|
252
|
+
: parseFloat(result.max);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Security-aware increment(): increments a column by a given value for all matching rows.
|
|
257
|
+
* Security rules are applied to determine which rows the user is allowed to modify.
|
|
258
|
+
*/
|
|
259
|
+
override async increment(where: FindOptionsWhere<T>, propertyPath: string, value: string | number,): Promise<UpdateResult> {
|
|
260
|
+
const alias = this.modelSingularName();
|
|
261
|
+
const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
|
|
262
|
+
|
|
263
|
+
qb.setFindOptions({ where });
|
|
264
|
+
|
|
265
|
+
const rows = await qb.select(`${alias}.id`).getMany();
|
|
266
|
+
const ids = rows.map((r) => (r as any).id);
|
|
267
|
+
|
|
268
|
+
if (ids.length === 0) {
|
|
269
|
+
return { raw: [], affected: 0, generatedMaps: [] };
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return this.manager
|
|
273
|
+
.createQueryBuilder()
|
|
274
|
+
.update(this.metadata.target)
|
|
275
|
+
.set({ [propertyPath]: () => `${propertyPath} + :value` } as any)
|
|
276
|
+
.whereInIds(ids)
|
|
277
|
+
.setParameter('value', value)
|
|
278
|
+
.execute();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Security-aware decrement(): decrements a column by a given value for all matching rows.
|
|
283
|
+
* Security rules are applied to determine which rows the user is allowed to modify.
|
|
284
|
+
*/
|
|
285
|
+
override async decrement(where: FindOptionsWhere<T>, propertyPath: string, value: string | number,): Promise<UpdateResult> {
|
|
286
|
+
const alias = this.modelSingularName();
|
|
287
|
+
const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
|
|
288
|
+
|
|
289
|
+
qb.setFindOptions({ where });
|
|
290
|
+
|
|
291
|
+
const rows = await qb.select(`${alias}.id`).getMany();
|
|
292
|
+
const ids = rows.map((r) => (r as any).id);
|
|
293
|
+
|
|
294
|
+
if (ids.length === 0) {
|
|
295
|
+
return { raw: [], affected: 0, generatedMaps: [] };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return this.manager
|
|
299
|
+
.createQueryBuilder()
|
|
300
|
+
.update(this.metadata.target)
|
|
301
|
+
.set({ [propertyPath]: () => `${propertyPath} - :value` } as any)
|
|
302
|
+
.whereInIds(ids)
|
|
303
|
+
.setParameter('value', value)
|
|
304
|
+
.execute();
|
|
305
|
+
}
|
|
135
306
|
}
|