@solidxai/core 0.1.10-beta.24 → 0.1.10-beta.26
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/controllers/action-metadata.controller.d.ts +1 -20
- package/dist/controllers/action-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/agent-event.controller.d.ts +1 -20
- package/dist/controllers/agent-event.controller.d.ts.map +1 -1
- package/dist/controllers/agent-session.controller.d.ts +1 -20
- package/dist/controllers/agent-session.controller.d.ts.map +1 -1
- package/dist/controllers/ai-interaction.controller.d.ts +1 -20
- package/dist/controllers/ai-interaction.controller.d.ts.map +1 -1
- package/dist/controllers/chatter-message-details.controller.d.ts +1 -20
- package/dist/controllers/chatter-message-details.controller.d.ts.map +1 -1
- package/dist/controllers/chatter-message.controller.d.ts +1 -20
- package/dist/controllers/chatter-message.controller.d.ts.map +1 -1
- package/dist/controllers/dashboard-user-layout.controller.d.ts +1 -20
- package/dist/controllers/dashboard-user-layout.controller.d.ts.map +1 -1
- package/dist/controllers/email-template.controller.d.ts +1 -20
- package/dist/controllers/email-template.controller.d.ts.map +1 -1
- package/dist/controllers/export-template.controller.d.ts +1 -20
- package/dist/controllers/export-template.controller.d.ts.map +1 -1
- package/dist/controllers/export-transaction.controller.d.ts +1 -20
- package/dist/controllers/export-transaction.controller.d.ts.map +1 -1
- package/dist/controllers/import-transaction-error-log.controller.d.ts +1 -20
- package/dist/controllers/import-transaction-error-log.controller.d.ts.map +1 -1
- package/dist/controllers/import-transaction.controller.d.ts +1 -20
- package/dist/controllers/import-transaction.controller.d.ts.map +1 -1
- package/dist/controllers/list-of-values.controller.d.ts +1 -20
- package/dist/controllers/list-of-values.controller.d.ts.map +1 -1
- package/dist/controllers/locale.controller.d.ts +1 -20
- package/dist/controllers/locale.controller.d.ts.map +1 -1
- package/dist/controllers/mcp-audit-log.controller.d.ts +1 -20
- package/dist/controllers/mcp-audit-log.controller.d.ts.map +1 -1
- package/dist/controllers/media.controller.d.ts +1 -20
- package/dist/controllers/media.controller.d.ts.map +1 -1
- package/dist/controllers/menu-item-metadata.controller.d.ts +1 -20
- package/dist/controllers/menu-item-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/model-metadata.controller.d.ts +10 -30
- package/dist/controllers/model-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/model-metadata.controller.js +2 -2
- package/dist/controllers/model-sequence.controller.d.ts +1 -20
- package/dist/controllers/model-sequence.controller.d.ts.map +1 -1
- package/dist/controllers/module-metadata-explorer.controller.d.ts +171 -0
- package/dist/controllers/module-metadata-explorer.controller.d.ts.map +1 -0
- package/dist/controllers/module-metadata-explorer.controller.js +143 -0
- package/dist/controllers/module-metadata-explorer.controller.js.map +1 -0
- package/dist/controllers/module-metadata.controller.d.ts +5 -0
- package/dist/controllers/module-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/module-metadata.controller.js +12 -0
- package/dist/controllers/module-metadata.controller.js.map +1 -1
- package/dist/controllers/module-package.controller.d.ts +622 -0
- package/dist/controllers/module-package.controller.d.ts.map +1 -0
- package/dist/controllers/module-package.controller.js +150 -0
- package/dist/controllers/module-package.controller.js.map +1 -0
- package/dist/controllers/mq-message-queue.controller.d.ts +1 -20
- package/dist/controllers/mq-message-queue.controller.d.ts.map +1 -1
- package/dist/controllers/mq-message.controller.d.ts +1 -20
- package/dist/controllers/mq-message.controller.d.ts.map +1 -1
- package/dist/controllers/permission-metadata.controller.d.ts +1 -20
- package/dist/controllers/permission-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/role-metadata.controller.d.ts +1 -20
- package/dist/controllers/role-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/saved-filters.controller.d.ts +1 -20
- package/dist/controllers/saved-filters.controller.d.ts.map +1 -1
- package/dist/controllers/scheduled-job.controller.d.ts +1 -20
- package/dist/controllers/scheduled-job.controller.d.ts.map +1 -1
- package/dist/controllers/security-rule.controller.d.ts +1 -20
- package/dist/controllers/security-rule.controller.d.ts.map +1 -1
- package/dist/controllers/sms-template.controller.d.ts +1 -20
- package/dist/controllers/sms-template.controller.d.ts.map +1 -1
- package/dist/controllers/user-activity-history.controller.d.ts +1 -20
- package/dist/controllers/user-activity-history.controller.d.ts.map +1 -1
- package/dist/controllers/user-view-metadata.controller.d.ts +1 -20
- package/dist/controllers/user-view-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/user.controller.d.ts +1 -20
- package/dist/controllers/user.controller.d.ts.map +1 -1
- package/dist/controllers/view-metadata.controller.d.ts +1 -20
- package/dist/controllers/view-metadata.controller.d.ts.map +1 -1
- package/dist/dtos/confirm-module-package-import.dto.d.ts +4 -0
- package/dist/dtos/confirm-module-package-import.dto.d.ts.map +1 -0
- package/dist/dtos/confirm-module-package-import.dto.js +34 -0
- package/dist/dtos/confirm-module-package-import.dto.js.map +1 -0
- package/dist/dtos/metadata-explorer-references-query.dto.d.ts +10 -0
- package/dist/dtos/metadata-explorer-references-query.dto.d.ts.map +1 -0
- package/dist/dtos/metadata-explorer-references-query.dto.js +69 -0
- package/dist/dtos/metadata-explorer-references-query.dto.js.map +1 -0
- package/dist/dtos/metadata-explorer-search-query.dto.d.ts +8 -0
- package/dist/dtos/metadata-explorer-search-query.dto.d.ts.map +1 -0
- package/dist/dtos/metadata-explorer-search-query.dto.js +55 -0
- package/dist/dtos/metadata-explorer-search-query.dto.js.map +1 -0
- package/dist/dtos/metadata-explorer-write.dto.d.ts +4 -0
- package/dist/dtos/metadata-explorer-write.dto.d.ts.map +1 -0
- package/dist/dtos/metadata-explorer-write.dto.js +30 -0
- package/dist/dtos/metadata-explorer-write.dto.js.map +1 -0
- package/dist/dtos/run-module-package-build.dto.d.ts +5 -0
- package/dist/dtos/run-module-package-build.dto.d.ts.map +1 -0
- package/dist/dtos/run-module-package-build.dto.js +38 -0
- package/dist/dtos/run-module-package-build.dto.js.map +1 -0
- package/dist/dtos/run-module-package-seed.dto.d.ts +4 -0
- package/dist/dtos/run-module-package-seed.dto.d.ts.map +1 -0
- package/dist/dtos/run-module-package-seed.dto.js +34 -0
- package/dist/dtos/run-module-package-seed.dto.js.map +1 -0
- package/dist/helpers/command.service.js +1 -1
- package/dist/helpers/command.service.js.map +1 -1
- package/dist/helpers/module-metadata-helper.service.d.ts +2 -0
- package/dist/helpers/module-metadata-helper.service.d.ts.map +1 -1
- package/dist/helpers/module-metadata-helper.service.js +14 -12
- package/dist/helpers/module-metadata-helper.service.js.map +1 -1
- package/dist/helpers/module.helper.d.ts.map +1 -1
- package/dist/helpers/module.helper.js +11 -6
- package/dist/helpers/module.helper.js.map +1 -1
- package/dist/helpers/typeorm-migration-helpers.d.ts +12 -0
- package/dist/helpers/typeorm-migration-helpers.d.ts.map +1 -0
- package/dist/helpers/typeorm-migration-helpers.js +119 -0
- package/dist/helpers/typeorm-migration-helpers.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts +1 -0
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +57 -38
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/module-test-data.service.js +1 -1
- package/dist/seeders/module-test-data.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +2364 -1106
- package/dist/services/crud-helper.service.d.ts +18 -0
- package/dist/services/crud-helper.service.d.ts.map +1 -1
- package/dist/services/crud-helper.service.js +67 -1
- package/dist/services/crud-helper.service.js.map +1 -1
- package/dist/services/crud.service.d.ts +1 -21
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +23 -87
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/genai/ingest-metadata.service.js +2 -2
- package/dist/services/genai/ingest-metadata.service.js.map +1 -1
- package/dist/services/media.service.d.ts +1 -20
- package/dist/services/media.service.d.ts.map +1 -1
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.d.ts.map +1 -1
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +31 -2
- 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 +5 -1
- package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
- package/dist/services/model-metadata.service.d.ts +15 -30
- package/dist/services/model-metadata.service.d.ts.map +1 -1
- package/dist/services/model-metadata.service.js +249 -29
- package/dist/services/model-metadata.service.js.map +1 -1
- package/dist/services/module-metadata-explorer.service.d.ts +161 -0
- package/dist/services/module-metadata-explorer.service.d.ts.map +1 -0
- package/dist/services/module-metadata-explorer.service.js +485 -0
- package/dist/services/module-metadata-explorer.service.js.map +1 -0
- package/dist/services/module-metadata.service.d.ts +7 -0
- package/dist/services/module-metadata.service.d.ts.map +1 -1
- package/dist/services/module-metadata.service.js +121 -2
- package/dist/services/module-metadata.service.js.map +1 -1
- package/dist/services/module-package.service.d.ts +266 -0
- package/dist/services/module-package.service.d.ts.map +1 -0
- package/dist/services/module-package.service.js +980 -0
- package/dist/services/module-package.service.js.map +1 -0
- package/dist/services/settings/default-settings-provider.service.d.ts +18 -0
- package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
- package/dist/services/settings/default-settings-provider.service.js +10 -0
- package/dist/services/settings/default-settings-provider.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +10 -2
- package/dist/solid-core.module.js.map +1 -1
- package/dist-tests/api/authenticate.spec.js +119 -0
- package/dist-tests/api/authenticate.spec.js.map +1 -0
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +97 -0
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +1 -0
- package/dist-tests/api/ping.spec.js +21 -0
- package/dist-tests/api/ping.spec.js.map +1 -0
- package/dist-tests/helpers/auth.js +41 -0
- package/dist-tests/helpers/auth.js.map +1 -0
- package/dist-tests/helpers/env.js +11 -0
- package/dist-tests/helpers/env.js.map +1 -0
- package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +438 -0
- package/docs/dashboards/dashboard-curl-smoke-tests.txt +146 -0
- package/docs/dashboards/delete-legacy-dashboard-metadata.sql +172 -0
- package/docs/grouping-enhancements.md +89 -0
- package/docs/java-spring/README.md +3 -0
- package/docs/java-spring/solid-core-module-deep-dive-report.md +1317 -0
- package/docs/module-package-import-handoff.md +691 -0
- package/docs/seed-changes.md +65 -0
- package/docs/test-data-workflow.md +200 -0
- package/docs/type-declaration-import-issue.md +24 -0
- package/package.json +2 -1
- package/src/controllers/module-metadata-explorer.controller.ts +83 -0
- package/src/controllers/module-metadata.controller.ts +6 -0
- package/src/controllers/module-package.controller.ts +102 -0
- package/src/dtos/confirm-module-package-import.dto.ts +12 -0
- package/src/dtos/metadata-explorer-references-query.dto.ts +39 -0
- package/src/dtos/metadata-explorer-search-query.dto.ts +28 -0
- package/src/dtos/metadata-explorer-write.dto.ts +11 -0
- package/src/dtos/run-module-package-build.dto.ts +14 -0
- package/src/dtos/run-module-package-seed.dto.ts +12 -0
- package/src/helpers/command.service.ts +1 -1
- package/src/helpers/module-metadata-helper.service.ts +19 -21
- package/src/helpers/module.helper.ts +12 -9
- package/src/helpers/typeorm-migration-helpers.ts +163 -0
- package/src/index.ts +8 -0
- package/src/seeders/module-metadata-seeder.service.ts +63 -38
- package/src/seeders/module-test-data.service.ts +1 -1
- package/src/seeders/seed-data/solid-core-metadata.json +2365 -1107
- package/src/services/crud-helper.service.ts +79 -1
- package/src/services/crud.service.ts +26 -119
- package/src/services/dashboard-providers/README.md +1 -1
- package/src/services/genai/ingest-metadata.service.ts +3 -3
- package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +37 -2
- package/src/services/mediaStorageProviders/file-storage-provider.ts +5 -1
- package/src/services/model-metadata.service.ts +302 -98
- package/src/services/module-metadata-explorer.service.ts +670 -0
- package/src/services/module-metadata.service.ts +136 -10
- package/src/services/module-package.service.ts +1171 -0
- package/src/services/settings/default-settings-provider.service.ts +10 -0
- package/src/solid-core.module.ts +10 -2
- package/.claude/settings.local.json +0 -15
- package/CLAUDE.md +0 -26
- package/dist/services/database/database-bootstrap.service.d.ts +0 -12
- package/dist/services/database/database-bootstrap.service.d.ts.map +0 -1
- package/dist/services/database/database-bootstrap.service.js +0 -115
- package/dist/services/database/database-bootstrap.service.js.map +0 -1
- package/sql/default/mariadb/proc_CleanupModelMetadata.sql +0 -153
- package/sql/default/mariadb/proc_CleanupModuleMetadata.sql +0 -56
- package/sql/default/mssql/proc_CleanupModuleMetadata.sql +0 -78
- package/sql/default/mysql/proc_CleanupModelMetadata.sql +0 -153
- package/sql/default/mysql/proc_CleanupModuleMetadata.sql +0 -56
- package/sql/default/postgres/proc_CleanupModelMetadata.sql +0 -148
- package/sql/default/postgres/proc_CleanupModuleMetadata.sql +0 -50
- package/sql/default/postgres/scratchpad.sql.txt +0 -12
- package/src/services/1.js +0 -6
- package/src/services/database/database-bootstrap.service.ts +0 -91
|
@@ -282,7 +282,13 @@ export class CrudHelperService {
|
|
|
282
282
|
const orderOptionKeys = Object.keys(orderOptions) as Array<keyof typeof orderOptions>;
|
|
283
283
|
orderOptionKeys.forEach((key) => {
|
|
284
284
|
const value = orderOptions[key] as 'ASC' | 'DESC';
|
|
285
|
-
|
|
285
|
+
const field = String(key);
|
|
286
|
+
if (field.includes('.')) {
|
|
287
|
+
const { alias, property } = this.ensureRelationPathJoined(qb, entityAlias, field.split('.'));
|
|
288
|
+
qb.addOrderBy(`${alias}.${property}`, value);
|
|
289
|
+
} else {
|
|
290
|
+
qb.addOrderBy(`${entityAlias}.${field}`, value);
|
|
291
|
+
}
|
|
286
292
|
});
|
|
287
293
|
}
|
|
288
294
|
}
|
|
@@ -743,4 +749,76 @@ export class CrudHelperService {
|
|
|
743
749
|
return matchingPermssions.length > 0
|
|
744
750
|
}
|
|
745
751
|
|
|
752
|
+
pagedResponse<T>(offset: number | undefined, limit: number | undefined, count: number, entities: T[]) {
|
|
753
|
+
const safeLimit = limit ?? count ?? 0;
|
|
754
|
+
const safeOffset = offset ?? 0;
|
|
755
|
+
const currentPage = safeLimit ? Math.floor(safeOffset / safeLimit) + 1 : 1;
|
|
756
|
+
const totalPages = safeLimit ? Math.ceil(count / safeLimit) : 1;
|
|
757
|
+
const nextPage = safeLimit && currentPage < totalPages ? currentPage + 1 : null;
|
|
758
|
+
const prevPage = safeLimit && currentPage > 1 ? currentPage - 1 : null;
|
|
759
|
+
return {
|
|
760
|
+
meta: {
|
|
761
|
+
totalRecords: count,
|
|
762
|
+
currentPage,
|
|
763
|
+
nextPage,
|
|
764
|
+
prevPage,
|
|
765
|
+
totalPages,
|
|
766
|
+
perPage: safeLimit ? +safeLimit : 0,
|
|
767
|
+
},
|
|
768
|
+
records: entities,
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
async executeGroupPipeline<T>(
|
|
773
|
+
filterQb: SelectQueryBuilder<T>,
|
|
774
|
+
basicFilterDto: BasicFilterDto,
|
|
775
|
+
alias: string,
|
|
776
|
+
createQbFn: () => Promise<SelectQueryBuilder<T>>,
|
|
777
|
+
postProcessEntities?: (entities: T[]) => Promise<void>
|
|
778
|
+
): Promise<{ meta: { totalRecords: number }; groupMeta: any[]; groupRecords: any[] }> {
|
|
779
|
+
const groupByFields = this.normalize(basicFilterDto.groupBy);
|
|
780
|
+
if (!groupByFields.length) throw new BadRequestException(ERROR_MESSAGES.INVALID_GROUP_BY_COUNT);
|
|
781
|
+
|
|
782
|
+
if (basicFilterDto.populateGroup) {
|
|
783
|
+
const hasRelationGroup = groupByFields.some(f => f.includes('.'));
|
|
784
|
+
if (hasRelationGroup) throw new BadRequestException('populateGroup is not supported when grouping on relation fields. Fetch group metadata first and retrieve records in a separate call.');
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
const { aliasMap: groupAliasMap, formatMap: groupFormatMap, expressionMap: groupExpressionMap } =
|
|
788
|
+
this.applyGroupBySelections(filterQb, groupByFields, alias);
|
|
789
|
+
const aggregateAliasMap = this.applyAggregates(filterQb, basicFilterDto.aggregates, alias);
|
|
790
|
+
this.applyGroupSortingAndPagination(filterQb, basicFilterDto.sort, { ...groupAliasMap, ...aggregateAliasMap }, basicFilterDto.limit, basicFilterDto.offset);
|
|
791
|
+
|
|
792
|
+
const groupByResult = await filterQb.getRawMany();
|
|
793
|
+
const totalGroups = await this.countGroups(filterQb);
|
|
794
|
+
const aggregateAliasSet = new Set(Object.values(aggregateAliasMap));
|
|
795
|
+
|
|
796
|
+
const groupMeta = [];
|
|
797
|
+
const groupRecords = [];
|
|
798
|
+
|
|
799
|
+
for (const group of groupByResult) {
|
|
800
|
+
groupMeta.push(this.createGroupMeta(group, aggregateAliasSet, groupByFields, groupAliasMap, groupFormatMap));
|
|
801
|
+
|
|
802
|
+
if (basicFilterDto.populateGroup) {
|
|
803
|
+
let groupQb = await createQbFn();
|
|
804
|
+
const { groupBy: _gb, aggregates: _agg, ...rest } = basicFilterDto;
|
|
805
|
+
const groupFilterDto: BasicFilterDto = {
|
|
806
|
+
...rest,
|
|
807
|
+
...basicFilterDto.groupFilter,
|
|
808
|
+
groupBy: undefined,
|
|
809
|
+
aggregates: undefined,
|
|
810
|
+
sort: basicFilterDto.groupFilter?.sort,
|
|
811
|
+
};
|
|
812
|
+
groupQb = this.buildFilterQuery(groupQb, groupFilterDto, alias);
|
|
813
|
+
groupQb = this.buildGroupByRecordsQuery(groupQb, group, alias, groupAliasMap, aggregateAliasMap, groupExpressionMap);
|
|
814
|
+
const [entities, count] = await groupQb.getManyAndCount();
|
|
815
|
+
if (postProcessEntities) await postProcessEntities(entities);
|
|
816
|
+
const groupData = this.pagedResponse(basicFilterDto.groupFilter?.offset, basicFilterDto.groupFilter?.limit, count, entities);
|
|
817
|
+
groupRecords.push(this.createGroupRecords(group, aggregateAliasSet, groupData, groupByFields, groupAliasMap, groupFormatMap));
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
return { meta: { totalRecords: totalGroups }, groupMeta, groupRecords };
|
|
822
|
+
}
|
|
823
|
+
|
|
746
824
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BadRequestException, InternalServerErrorException, NotFoundException } from "@nestjs/common";
|
|
1
|
+
import { BadRequestException, ConflictException, HttpException, InternalServerErrorException, NotFoundException } from "@nestjs/common";
|
|
2
2
|
import { DiscoveryService, ModuleRef } from "@nestjs/core";
|
|
3
3
|
import { isArray } from "class-validator";
|
|
4
4
|
import { CommonEntity } from "../entities/common.entity";
|
|
@@ -41,7 +41,6 @@ import { SolidRegistry } from "src/helpers/solid-registry";
|
|
|
41
41
|
import { getMediaStorageProvider } from "./mediaStorageProviders";
|
|
42
42
|
import { ModelMetadataService } from "./model-metadata.service";
|
|
43
43
|
import { RequestContextService } from "./request-context.service";
|
|
44
|
-
import { BasicGroupFilterDto } from "src/dtos/basic-group-filters.dto";
|
|
45
44
|
|
|
46
45
|
|
|
47
46
|
export class CRUDService<T extends CommonEntity> { // Add two generic value i.e Person,CreatePersonDto, so we get the proper types in our service
|
|
@@ -480,10 +479,10 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
|
|
|
480
479
|
return false; // If it is not a partial update, then do not skip computation
|
|
481
480
|
}
|
|
482
481
|
|
|
483
|
-
async find(basicFilterDto: BasicFilterDto, solidRequestContext: any = {}) {
|
|
482
|
+
async find(basicFilterDto: BasicFilterDto, solidRequestContext: any = {}): Promise<any> {
|
|
484
483
|
const alias = 'entity';
|
|
485
484
|
// Extract the required keys from the input query
|
|
486
|
-
let { limit, offset, populateMedia
|
|
485
|
+
let { limit, offset, populateMedia } = basicFilterDto;
|
|
487
486
|
const populateUserIdFields = this.crudHelperService.extractUserIdFieldsFromPopulate(basicFilterDto.populate);
|
|
488
487
|
|
|
489
488
|
const { singularName, internationalisation, draftPublishWorkflow } = await this.loadModel();
|
|
@@ -502,41 +501,19 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
|
|
|
502
501
|
// Create above query on pincode table using query builder
|
|
503
502
|
var qb: SelectQueryBuilder<T> = await this.repo.createSecurityRuleAwareQueryBuilder(alias)
|
|
504
503
|
|
|
505
|
-
if (basicFilterDto.groupBy) {
|
|
504
|
+
if (basicFilterDto.groupBy?.length) {
|
|
506
505
|
const groupFilterQb = (internationalisation && draftPublishWorkflow)
|
|
507
506
|
? this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, internationalisation, draftPublishWorkflow, this.moduleRef, FilterCombinator.AND, false, false)
|
|
508
507
|
: this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, undefined, undefined, undefined, FilterCombinator.AND, false, false);
|
|
509
508
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
const hasRelationGroup = groupByFields.some(field => field.includes('.'));
|
|
517
|
-
if (hasRelationGroup) {
|
|
518
|
-
throw new BadRequestException('populateGroup is not supported when grouping on relation fields. Fetch group metadata first and retrieve records in a separate call.');
|
|
509
|
+
return this.crudHelperService.executeGroupPipeline(
|
|
510
|
+
groupFilterQb, basicFilterDto, alias,
|
|
511
|
+
() => this.repo.createSecurityRuleAwareQueryBuilder(alias),
|
|
512
|
+
async (entities) => {
|
|
513
|
+
if (populateUserIdFields?.length) await this.handlePopulateUserIdFields(populateUserIdFields, entities);
|
|
514
|
+
if (populateMedia?.length) await this.handlePopulateMedia(populateMedia, entities);
|
|
519
515
|
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
const { aliasMap: groupAliasMap, formatMap: groupFormatMap, expressionMap: groupExpressionMap } = this.crudHelperService.applyGroupBySelections(groupFilterQb, groupByFields, alias);
|
|
523
|
-
const aggregateAliasMap = this.crudHelperService.applyAggregates(groupFilterQb, basicFilterDto.aggregates, alias);
|
|
524
|
-
const sortAliasMap = { ...groupAliasMap, ...aggregateAliasMap };
|
|
525
|
-
this.crudHelperService.applyGroupSortingAndPagination(groupFilterQb, basicFilterDto.sort, sortAliasMap, limit, offset);
|
|
526
|
-
|
|
527
|
-
const groupByResult = await groupFilterQb.getRawMany();
|
|
528
|
-
const totalGroups = await this.crudHelperService.countGroups(groupFilterQb);
|
|
529
|
-
|
|
530
|
-
const groupByFieldsOrdered = this.crudHelperService.normalize(basicFilterDto.groupBy || []);
|
|
531
|
-
const { groupMeta, groupRecords } = await this.handleGroupFind(groupByResult, groupFilter, populateGroup, alias, populateUserIdFields, populateMedia, basicFilterDto, groupAliasMap, aggregateAliasMap, groupByFieldsOrdered, groupFormatMap, groupExpressionMap);
|
|
532
|
-
|
|
533
|
-
return {
|
|
534
|
-
meta: {
|
|
535
|
-
"totalRecords": totalGroups
|
|
536
|
-
},
|
|
537
|
-
groupMeta,
|
|
538
|
-
groupRecords,
|
|
539
|
-
}
|
|
516
|
+
);
|
|
540
517
|
}
|
|
541
518
|
else {
|
|
542
519
|
qb = (internationalisation && draftPublishWorkflow)
|
|
@@ -566,78 +543,8 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
|
|
|
566
543
|
return this.wrapFindResponse(offset, limit, count, entities);
|
|
567
544
|
}
|
|
568
545
|
|
|
569
|
-
private async handleGroupFind(
|
|
570
|
-
groupByResult: any[],
|
|
571
|
-
groupFilter: BasicGroupFilterDto | undefined,
|
|
572
|
-
populateGroup: boolean,
|
|
573
|
-
alias: string,
|
|
574
|
-
populateUserIdFields: UserIdFields[],
|
|
575
|
-
populateMedia: string[],
|
|
576
|
-
baseFilterDto: BasicFilterDto,
|
|
577
|
-
groupAliasMap: Record<string, string>,
|
|
578
|
-
aggregateAliasMap: Record<string, string>,
|
|
579
|
-
groupByFieldsOrdered: string[],
|
|
580
|
-
groupFormatMap: Record<string, string | undefined>,
|
|
581
|
-
groupExpressionMap: Record<string, string>
|
|
582
|
-
) {
|
|
583
|
-
const groupMeta = [];
|
|
584
|
-
const groupRecords = [];
|
|
585
|
-
const aggregateAliasSet = new Set(Object.values(aggregateAliasMap));
|
|
586
|
-
// For each group, get the records and the count
|
|
587
|
-
for (const group of groupByResult) {
|
|
588
|
-
if (populateGroup) {
|
|
589
|
-
let groupByQb: SelectQueryBuilder<T> = await this.repo.createSecurityRuleAwareQueryBuilder(alias);
|
|
590
|
-
const groupFilterDto: BasicFilterDto = {
|
|
591
|
-
...baseFilterDto,
|
|
592
|
-
...groupFilter,
|
|
593
|
-
groupBy: undefined,
|
|
594
|
-
aggregates: undefined,
|
|
595
|
-
// Only use explicit groupFilter.sort for record ordering; group-level sorts can contain
|
|
596
|
-
// group expressions (e.g. createdAt:day) that are invalid on record queries.
|
|
597
|
-
sort: groupFilter?.sort,
|
|
598
|
-
};
|
|
599
|
-
groupByQb = this.crudHelperService.buildFilterQuery(groupByQb, groupFilterDto, alias);
|
|
600
|
-
groupByQb = this.crudHelperService.buildGroupByRecordsQuery(groupByQb, group, alias, groupAliasMap, aggregateAliasMap, groupExpressionMap);
|
|
601
|
-
const [entities, count] = await groupByQb.getManyAndCount();
|
|
602
|
-
|
|
603
|
-
// Populate the entity with the userId fields
|
|
604
|
-
if (populateUserIdFields && populateUserIdFields.length > 0) {
|
|
605
|
-
await this.handlePopulateUserIdFields(populateUserIdFields, entities);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
// Populate the entity with the media
|
|
609
|
-
if (populateMedia && populateMedia.length > 0) {
|
|
610
|
-
await this.handlePopulateMedia(populateMedia, entities);
|
|
611
|
-
}
|
|
612
|
-
const groupData = this.wrapFindResponse(groupFilter?.offset, groupFilter?.limit, count, entities);
|
|
613
|
-
groupRecords.push(this.crudHelperService.createGroupRecords(group, aggregateAliasSet, groupData, groupByFieldsOrdered, groupAliasMap, groupFormatMap));
|
|
614
|
-
}
|
|
615
|
-
groupMeta.push(this.crudHelperService.createGroupMeta(group, aggregateAliasSet, groupByFieldsOrdered, groupAliasMap, groupFormatMap));
|
|
616
|
-
}
|
|
617
|
-
return { groupMeta, groupRecords };
|
|
618
|
-
}
|
|
619
|
-
|
|
620
546
|
private wrapFindResponse(offset: number | undefined, limit: number | undefined, count: number, entities: T[]) {
|
|
621
|
-
|
|
622
|
-
const safeOffset = offset ?? 0;
|
|
623
|
-
const currentPage = safeLimit ? Math.floor(safeOffset / safeLimit) + 1 : 1;
|
|
624
|
-
const totalPages = safeLimit ? Math.ceil(count / safeLimit) : 1;
|
|
625
|
-
|
|
626
|
-
const nextPage = safeLimit && currentPage < totalPages ? currentPage + 1 : null;
|
|
627
|
-
const prevPage = safeLimit && currentPage > 1 ? currentPage - 1 : null;
|
|
628
|
-
|
|
629
|
-
const r = {
|
|
630
|
-
meta: {
|
|
631
|
-
totalRecords: count,
|
|
632
|
-
currentPage: currentPage,
|
|
633
|
-
nextPage: nextPage,
|
|
634
|
-
prevPage: prevPage,
|
|
635
|
-
totalPages: totalPages,
|
|
636
|
-
perPage: safeLimit ? +safeLimit : 0,
|
|
637
|
-
},
|
|
638
|
-
records: entities
|
|
639
|
-
};
|
|
640
|
-
return r;
|
|
547
|
+
return this.crudHelperService.pagedResponse(offset, limit, count, entities);
|
|
641
548
|
}
|
|
642
549
|
|
|
643
550
|
// entities is an array of T
|
|
@@ -911,7 +818,7 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
|
|
|
911
818
|
});
|
|
912
819
|
|
|
913
820
|
if (!softDeletedRows) {
|
|
914
|
-
throw new
|
|
821
|
+
throw new NotFoundException(ERROR_MESSAGES.NO_SOFT_DELETED_RECORD_FOUND);
|
|
915
822
|
}
|
|
916
823
|
|
|
917
824
|
await this.repo.update(id, {
|
|
@@ -921,13 +828,13 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
|
|
|
921
828
|
|
|
922
829
|
return { message: SUCCESS_MESSAGES.RECORD_RECOVERED, data: softDeletedRows };
|
|
923
830
|
} catch (error: any) {
|
|
924
|
-
if (error instanceof QueryFailedError) {
|
|
925
|
-
|
|
926
|
-
throw new Error(ERROR_MESSAGES.CONFLICTING_RECORD_ON_UNARCHIVE);
|
|
927
|
-
}
|
|
831
|
+
if (error instanceof QueryFailedError && (error as any).code === '23505') {
|
|
832
|
+
throw new ConflictException(ERROR_MESSAGES.CONFLICTING_RECORD_ON_UNARCHIVE);
|
|
928
833
|
}
|
|
929
|
-
|
|
930
|
-
|
|
834
|
+
if (error instanceof HttpException) {
|
|
835
|
+
throw error;
|
|
836
|
+
}
|
|
837
|
+
throw new InternalServerErrorException(error?.message ?? String(error));
|
|
931
838
|
}
|
|
932
839
|
}
|
|
933
840
|
|
|
@@ -956,7 +863,7 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
|
|
|
956
863
|
});
|
|
957
864
|
|
|
958
865
|
if (softDeletedRows.length === 0) {
|
|
959
|
-
throw new
|
|
866
|
+
throw new NotFoundException(ERROR_MESSAGES.NO_SOFT_DELETED_RECORDS_FOUND);
|
|
960
867
|
}
|
|
961
868
|
|
|
962
869
|
// Recover the specific records by setting deletedAt to null
|
|
@@ -967,13 +874,13 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
|
|
|
967
874
|
|
|
968
875
|
return { message: SUCCESS_MESSAGES.SELECTED_RECORDS_RECOVERED, recoveredIds: ids };
|
|
969
876
|
} catch (error: any) {
|
|
970
|
-
if (error instanceof QueryFailedError) {
|
|
971
|
-
|
|
972
|
-
throw new Error(ERROR_MESSAGES.CONFLICTING_RECORD_ON_UNARCHIVE);
|
|
973
|
-
}
|
|
877
|
+
if (error instanceof QueryFailedError && (error as any).code === "23505") {
|
|
878
|
+
throw new ConflictException(ERROR_MESSAGES.CONFLICTING_RECORD_ON_UNARCHIVE);
|
|
974
879
|
}
|
|
975
|
-
|
|
976
|
-
|
|
880
|
+
if (error instanceof HttpException) {
|
|
881
|
+
throw error;
|
|
882
|
+
}
|
|
883
|
+
throw new InternalServerErrorException(error?.message ?? String(error));
|
|
977
884
|
}
|
|
978
885
|
}
|
|
979
886
|
|
|
@@ -38,7 +38,7 @@ Not persisted:
|
|
|
38
38
|
|
|
39
39
|
At runtime, metadata is read from file paths resolved by `ModuleMetadataHelperService`:
|
|
40
40
|
|
|
41
|
-
1. `module-metadata/<module-name
|
|
41
|
+
1. `src/<module-name>/metadata/<module-name>-metadata.json`
|
|
42
42
|
2. fallback (solid-core local run): `src/seeders/seed-data/solid-core-metadata.json`
|
|
43
43
|
3. fallback (consuming project): `node_modules/@solidxai/core/src/seeders/seed-data/solid-core-metadata.json`
|
|
44
44
|
|
|
@@ -97,14 +97,14 @@ export class IngestMetadataService {
|
|
|
97
97
|
for (let i = 0; i < enabledModules.length; i++) {
|
|
98
98
|
const enabledModule = enabledModules[i];
|
|
99
99
|
const fileName = `${enabledModule}-metadata.json`;
|
|
100
|
-
const enabledModuleSeedFile = `
|
|
100
|
+
const enabledModuleSeedFile = `src/${enabledModule}/metadata/${fileName}`;
|
|
101
101
|
const fullPath = path.join(process.cwd(), enabledModuleSeedFile);
|
|
102
102
|
const overallMetadata: any = JSON.parse(fs.readFileSync(fullPath, 'utf-8').toString());
|
|
103
103
|
|
|
104
104
|
const moduleMetadata: CreateModuleMetadataDto = overallMetadata.moduleMetadata;
|
|
105
105
|
|
|
106
106
|
// Manage all the ingestion info file paths...
|
|
107
|
-
const enabledModulIngestionInfoFile = `
|
|
107
|
+
const enabledModulIngestionInfoFile = `src/${enabledModule}/metadata/genai/${enabledModule}-ingested-info.json`;
|
|
108
108
|
const enabledModulIngestionInfoFullPath = path.join(process.cwd(), enabledModulIngestionInfoFile);
|
|
109
109
|
const ingestionInfo: ModuleRAGIngestionInfo = fs.existsSync(enabledModulIngestionInfoFullPath) ? JSON.parse(fs.readFileSync(enabledModulIngestionInfoFullPath, 'utf-8').toString()) : {};
|
|
110
110
|
const enabledModulIngestionInfoDir = path.dirname(enabledModulIngestionInfoFullPath);
|
|
@@ -795,4 +795,4 @@ ${JSON.stringify(model)}
|
|
|
795
795
|
this.logger.log(`[OK] Ingested field ${moduleName}.${modelName}.${fieldName} → id=${newId}, hash=${schemaHash.slice(0, 8)}…`);
|
|
796
796
|
return newId;
|
|
797
797
|
}
|
|
798
|
-
}
|
|
798
|
+
}
|
|
@@ -21,8 +21,43 @@ export class FileS3StorageProvider<T> implements MediaStorageProvider<T> {
|
|
|
21
21
|
readonly mediaRepository: MediaRepository,
|
|
22
22
|
) { }
|
|
23
23
|
|
|
24
|
-
storeStreams(streamPairs: [Readable, string][], entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]> {
|
|
25
|
-
|
|
24
|
+
async storeStreams(streamPairs: [Readable, string][], entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]> {
|
|
25
|
+
const isSupportedEntity = entity instanceof CommonEntity
|
|
26
|
+
|| entity instanceof LegacyCommonEntityWithExistingId
|
|
27
|
+
|| entity instanceof LegacyCommonEntityWithGeneratedId;
|
|
28
|
+
if (!isSupportedEntity) {
|
|
29
|
+
throw new Error("Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId");
|
|
30
|
+
}
|
|
31
|
+
const result: Media[] = [];
|
|
32
|
+
const storageProvider = mediaFieldMetadata.mediaStorageProvider;
|
|
33
|
+
const region = this.getEffectiveRegion(storageProvider.region);
|
|
34
|
+
|
|
35
|
+
for (const [stream, fileName] of streamPairs) {
|
|
36
|
+
const bucketName = storageProvider.bucketName;
|
|
37
|
+
|
|
38
|
+
// Buffer the stream so we can get the byte count and upload in one pass
|
|
39
|
+
const chunks: Buffer[] = [];
|
|
40
|
+
for await (const chunk of stream) {
|
|
41
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
42
|
+
}
|
|
43
|
+
const fileData = Buffer.concat(chunks);
|
|
44
|
+
const fileSize = fileData.length;
|
|
45
|
+
|
|
46
|
+
await this.s3FileService.write(`${bucketName}:${fileName}`, fileData, { region });
|
|
47
|
+
|
|
48
|
+
const mediaEntity = await this.mediaRepository.createMedia({
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
entityId: entity.id,
|
|
51
|
+
modelMetadataId: mediaFieldMetadata.model.id,
|
|
52
|
+
relativeUri: fileName,
|
|
53
|
+
fileSize,
|
|
54
|
+
mediaStorageProviderMetadataId: mediaFieldMetadata.mediaStorageProvider.id,
|
|
55
|
+
fieldMetadataId: mediaFieldMetadata.id
|
|
56
|
+
}) as unknown as Media;
|
|
57
|
+
result.push(mediaEntity);
|
|
58
|
+
this.logger.debug(`Stored media with`, mediaEntity);
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
26
61
|
}
|
|
27
62
|
|
|
28
63
|
async retrieve(entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]> {
|
|
@@ -8,6 +8,7 @@ import { MediaRepository } from "src/repository/media.repository";
|
|
|
8
8
|
import { DiskFileService } from "src/services/file";
|
|
9
9
|
import { Readable } from "stream";
|
|
10
10
|
import * as path from "path";
|
|
11
|
+
import * as fs from "fs";
|
|
11
12
|
import { SettingService } from "../setting.service";
|
|
12
13
|
import { DEFAULT_MEDIA_FILE_STORAGE_DIR } from "src/services/settings/default-settings-provider.service";
|
|
13
14
|
import type { SolidCoreSetting } from "src/services/settings/default-settings-provider.service";
|
|
@@ -80,12 +81,15 @@ export class FileStorageProvider<T> implements MediaStorageProvider<T> {
|
|
|
80
81
|
for (const pair of streamPairs) {
|
|
81
82
|
const stream = pair[0];
|
|
82
83
|
const fileName = pair[1];
|
|
83
|
-
|
|
84
|
+
const fullPath = this.getFullFilePath(fileName);
|
|
85
|
+
await this.fileService.writeStream(fullPath, stream);
|
|
86
|
+
const { size: fileSize } = await fs.promises.stat(fullPath);
|
|
84
87
|
const mediaEntity = await this.mediaRepository.createMedia({
|
|
85
88
|
//@ts-ignore
|
|
86
89
|
entityId: entity.id,
|
|
87
90
|
modelMetadataId: mediaFieldMetadata.model.id,
|
|
88
91
|
relativeUri: fileName,
|
|
92
|
+
fileSize,
|
|
89
93
|
mediaStorageProviderMetadataId: mediaFieldMetadata.mediaStorageProvider.id,
|
|
90
94
|
fieldMetadataId: mediaFieldMetadata.id
|
|
91
95
|
}) as unknown as Media;
|