@solidxai/core 0.1.10-beta.25 → 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.
Files changed (225) hide show
  1. package/dist/controllers/action-metadata.controller.d.ts +1 -20
  2. package/dist/controllers/action-metadata.controller.d.ts.map +1 -1
  3. package/dist/controllers/agent-event.controller.d.ts +1 -20
  4. package/dist/controllers/agent-event.controller.d.ts.map +1 -1
  5. package/dist/controllers/agent-session.controller.d.ts +1 -20
  6. package/dist/controllers/agent-session.controller.d.ts.map +1 -1
  7. package/dist/controllers/ai-interaction.controller.d.ts +1 -20
  8. package/dist/controllers/ai-interaction.controller.d.ts.map +1 -1
  9. package/dist/controllers/chatter-message-details.controller.d.ts +1 -20
  10. package/dist/controllers/chatter-message-details.controller.d.ts.map +1 -1
  11. package/dist/controllers/chatter-message.controller.d.ts +1 -20
  12. package/dist/controllers/chatter-message.controller.d.ts.map +1 -1
  13. package/dist/controllers/dashboard-user-layout.controller.d.ts +1 -20
  14. package/dist/controllers/dashboard-user-layout.controller.d.ts.map +1 -1
  15. package/dist/controllers/email-template.controller.d.ts +1 -20
  16. package/dist/controllers/email-template.controller.d.ts.map +1 -1
  17. package/dist/controllers/export-template.controller.d.ts +1 -20
  18. package/dist/controllers/export-template.controller.d.ts.map +1 -1
  19. package/dist/controllers/export-transaction.controller.d.ts +1 -20
  20. package/dist/controllers/export-transaction.controller.d.ts.map +1 -1
  21. package/dist/controllers/import-transaction-error-log.controller.d.ts +1 -20
  22. package/dist/controllers/import-transaction-error-log.controller.d.ts.map +1 -1
  23. package/dist/controllers/import-transaction.controller.d.ts +1 -20
  24. package/dist/controllers/import-transaction.controller.d.ts.map +1 -1
  25. package/dist/controllers/list-of-values.controller.d.ts +1 -20
  26. package/dist/controllers/list-of-values.controller.d.ts.map +1 -1
  27. package/dist/controllers/locale.controller.d.ts +1 -20
  28. package/dist/controllers/locale.controller.d.ts.map +1 -1
  29. package/dist/controllers/mcp-audit-log.controller.d.ts +1 -20
  30. package/dist/controllers/mcp-audit-log.controller.d.ts.map +1 -1
  31. package/dist/controllers/media.controller.d.ts +1 -20
  32. package/dist/controllers/media.controller.d.ts.map +1 -1
  33. package/dist/controllers/menu-item-metadata.controller.d.ts +1 -20
  34. package/dist/controllers/menu-item-metadata.controller.d.ts.map +1 -1
  35. package/dist/controllers/model-metadata.controller.d.ts +10 -30
  36. package/dist/controllers/model-metadata.controller.d.ts.map +1 -1
  37. package/dist/controllers/model-metadata.controller.js +2 -2
  38. package/dist/controllers/model-sequence.controller.d.ts +1 -20
  39. package/dist/controllers/model-sequence.controller.d.ts.map +1 -1
  40. package/dist/controllers/module-metadata-explorer.controller.d.ts +171 -0
  41. package/dist/controllers/module-metadata-explorer.controller.d.ts.map +1 -0
  42. package/dist/controllers/module-metadata-explorer.controller.js +143 -0
  43. package/dist/controllers/module-metadata-explorer.controller.js.map +1 -0
  44. package/dist/controllers/module-metadata.controller.d.ts +5 -0
  45. package/dist/controllers/module-metadata.controller.d.ts.map +1 -1
  46. package/dist/controllers/module-metadata.controller.js +12 -0
  47. package/dist/controllers/module-metadata.controller.js.map +1 -1
  48. package/dist/controllers/module-package.controller.d.ts +622 -0
  49. package/dist/controllers/module-package.controller.d.ts.map +1 -0
  50. package/dist/controllers/module-package.controller.js +150 -0
  51. package/dist/controllers/module-package.controller.js.map +1 -0
  52. package/dist/controllers/mq-message-queue.controller.d.ts +1 -20
  53. package/dist/controllers/mq-message-queue.controller.d.ts.map +1 -1
  54. package/dist/controllers/mq-message.controller.d.ts +1 -20
  55. package/dist/controllers/mq-message.controller.d.ts.map +1 -1
  56. package/dist/controllers/permission-metadata.controller.d.ts +1 -20
  57. package/dist/controllers/permission-metadata.controller.d.ts.map +1 -1
  58. package/dist/controllers/role-metadata.controller.d.ts +1 -20
  59. package/dist/controllers/role-metadata.controller.d.ts.map +1 -1
  60. package/dist/controllers/saved-filters.controller.d.ts +1 -20
  61. package/dist/controllers/saved-filters.controller.d.ts.map +1 -1
  62. package/dist/controllers/scheduled-job.controller.d.ts +1 -20
  63. package/dist/controllers/scheduled-job.controller.d.ts.map +1 -1
  64. package/dist/controllers/security-rule.controller.d.ts +1 -20
  65. package/dist/controllers/security-rule.controller.d.ts.map +1 -1
  66. package/dist/controllers/sms-template.controller.d.ts +1 -20
  67. package/dist/controllers/sms-template.controller.d.ts.map +1 -1
  68. package/dist/controllers/user-activity-history.controller.d.ts +1 -20
  69. package/dist/controllers/user-activity-history.controller.d.ts.map +1 -1
  70. package/dist/controllers/user-view-metadata.controller.d.ts +1 -20
  71. package/dist/controllers/user-view-metadata.controller.d.ts.map +1 -1
  72. package/dist/controllers/user.controller.d.ts +1 -20
  73. package/dist/controllers/user.controller.d.ts.map +1 -1
  74. package/dist/controllers/view-metadata.controller.d.ts +1 -20
  75. package/dist/controllers/view-metadata.controller.d.ts.map +1 -1
  76. package/dist/dtos/confirm-module-package-import.dto.d.ts +4 -0
  77. package/dist/dtos/confirm-module-package-import.dto.d.ts.map +1 -0
  78. package/dist/dtos/confirm-module-package-import.dto.js +34 -0
  79. package/dist/dtos/confirm-module-package-import.dto.js.map +1 -0
  80. package/dist/dtos/metadata-explorer-references-query.dto.d.ts +10 -0
  81. package/dist/dtos/metadata-explorer-references-query.dto.d.ts.map +1 -0
  82. package/dist/dtos/metadata-explorer-references-query.dto.js +69 -0
  83. package/dist/dtos/metadata-explorer-references-query.dto.js.map +1 -0
  84. package/dist/dtos/metadata-explorer-search-query.dto.d.ts +8 -0
  85. package/dist/dtos/metadata-explorer-search-query.dto.d.ts.map +1 -0
  86. package/dist/dtos/metadata-explorer-search-query.dto.js +55 -0
  87. package/dist/dtos/metadata-explorer-search-query.dto.js.map +1 -0
  88. package/dist/dtos/metadata-explorer-write.dto.d.ts +4 -0
  89. package/dist/dtos/metadata-explorer-write.dto.d.ts.map +1 -0
  90. package/dist/dtos/metadata-explorer-write.dto.js +30 -0
  91. package/dist/dtos/metadata-explorer-write.dto.js.map +1 -0
  92. package/dist/dtos/run-module-package-build.dto.d.ts +5 -0
  93. package/dist/dtos/run-module-package-build.dto.d.ts.map +1 -0
  94. package/dist/dtos/run-module-package-build.dto.js +38 -0
  95. package/dist/dtos/run-module-package-build.dto.js.map +1 -0
  96. package/dist/dtos/run-module-package-seed.dto.d.ts +4 -0
  97. package/dist/dtos/run-module-package-seed.dto.d.ts.map +1 -0
  98. package/dist/dtos/run-module-package-seed.dto.js +34 -0
  99. package/dist/dtos/run-module-package-seed.dto.js.map +1 -0
  100. package/dist/helpers/command.service.js +1 -1
  101. package/dist/helpers/command.service.js.map +1 -1
  102. package/dist/helpers/module-metadata-helper.service.d.ts +2 -0
  103. package/dist/helpers/module-metadata-helper.service.d.ts.map +1 -1
  104. package/dist/helpers/module-metadata-helper.service.js +14 -12
  105. package/dist/helpers/module-metadata-helper.service.js.map +1 -1
  106. package/dist/helpers/module.helper.d.ts.map +1 -1
  107. package/dist/helpers/module.helper.js +11 -6
  108. package/dist/helpers/module.helper.js.map +1 -1
  109. package/dist/helpers/typeorm-migration-helpers.d.ts +12 -0
  110. package/dist/helpers/typeorm-migration-helpers.d.ts.map +1 -0
  111. package/dist/helpers/typeorm-migration-helpers.js +119 -0
  112. package/dist/helpers/typeorm-migration-helpers.js.map +1 -0
  113. package/dist/index.d.ts +8 -0
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.js +8 -0
  116. package/dist/index.js.map +1 -1
  117. package/dist/seeders/module-metadata-seeder.service.d.ts +1 -0
  118. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  119. package/dist/seeders/module-metadata-seeder.service.js +57 -38
  120. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  121. package/dist/seeders/module-test-data.service.js +1 -1
  122. package/dist/seeders/module-test-data.service.js.map +1 -1
  123. package/dist/seeders/seed-data/solid-core-metadata.json +2364 -1106
  124. package/dist/services/crud-helper.service.d.ts +18 -0
  125. package/dist/services/crud-helper.service.d.ts.map +1 -1
  126. package/dist/services/crud-helper.service.js +59 -0
  127. package/dist/services/crud-helper.service.js.map +1 -1
  128. package/dist/services/crud.service.d.ts +1 -21
  129. package/dist/services/crud.service.d.ts.map +1 -1
  130. package/dist/services/crud.service.js +9 -75
  131. package/dist/services/crud.service.js.map +1 -1
  132. package/dist/services/genai/ingest-metadata.service.js +2 -2
  133. package/dist/services/genai/ingest-metadata.service.js.map +1 -1
  134. package/dist/services/media.service.d.ts +1 -20
  135. package/dist/services/media.service.d.ts.map +1 -1
  136. package/dist/services/mediaStorageProviders/file-s3-storage-provider.d.ts.map +1 -1
  137. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +31 -2
  138. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
  139. package/dist/services/mediaStorageProviders/file-storage-provider.d.ts.map +1 -1
  140. package/dist/services/mediaStorageProviders/file-storage-provider.js +5 -1
  141. package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
  142. package/dist/services/model-metadata.service.d.ts +15 -30
  143. package/dist/services/model-metadata.service.d.ts.map +1 -1
  144. package/dist/services/model-metadata.service.js +249 -29
  145. package/dist/services/model-metadata.service.js.map +1 -1
  146. package/dist/services/module-metadata-explorer.service.d.ts +161 -0
  147. package/dist/services/module-metadata-explorer.service.d.ts.map +1 -0
  148. package/dist/services/module-metadata-explorer.service.js +485 -0
  149. package/dist/services/module-metadata-explorer.service.js.map +1 -0
  150. package/dist/services/module-metadata.service.d.ts +7 -0
  151. package/dist/services/module-metadata.service.d.ts.map +1 -1
  152. package/dist/services/module-metadata.service.js +121 -2
  153. package/dist/services/module-metadata.service.js.map +1 -1
  154. package/dist/services/module-package.service.d.ts +266 -0
  155. package/dist/services/module-package.service.d.ts.map +1 -0
  156. package/dist/services/module-package.service.js +980 -0
  157. package/dist/services/module-package.service.js.map +1 -0
  158. package/dist/solid-core.module.d.ts.map +1 -1
  159. package/dist/solid-core.module.js +10 -2
  160. package/dist/solid-core.module.js.map +1 -1
  161. package/dist-tests/api/authenticate.spec.js +119 -0
  162. package/dist-tests/api/authenticate.spec.js.map +1 -0
  163. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +97 -0
  164. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +1 -0
  165. package/dist-tests/api/ping.spec.js +21 -0
  166. package/dist-tests/api/ping.spec.js.map +1 -0
  167. package/dist-tests/helpers/auth.js +41 -0
  168. package/dist-tests/helpers/auth.js.map +1 -0
  169. package/dist-tests/helpers/env.js +11 -0
  170. package/dist-tests/helpers/env.js.map +1 -0
  171. package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +438 -0
  172. package/docs/dashboards/dashboard-curl-smoke-tests.txt +146 -0
  173. package/docs/dashboards/delete-legacy-dashboard-metadata.sql +172 -0
  174. package/docs/grouping-enhancements.md +89 -0
  175. package/docs/java-spring/README.md +3 -0
  176. package/docs/java-spring/solid-core-module-deep-dive-report.md +1317 -0
  177. package/docs/module-package-import-handoff.md +691 -0
  178. package/docs/seed-changes.md +65 -0
  179. package/docs/test-data-workflow.md +200 -0
  180. package/docs/type-declaration-import-issue.md +24 -0
  181. package/package.json +2 -1
  182. package/src/controllers/module-metadata-explorer.controller.ts +83 -0
  183. package/src/controllers/module-metadata.controller.ts +6 -0
  184. package/src/controllers/module-package.controller.ts +102 -0
  185. package/src/dtos/confirm-module-package-import.dto.ts +12 -0
  186. package/src/dtos/metadata-explorer-references-query.dto.ts +39 -0
  187. package/src/dtos/metadata-explorer-search-query.dto.ts +28 -0
  188. package/src/dtos/metadata-explorer-write.dto.ts +11 -0
  189. package/src/dtos/run-module-package-build.dto.ts +14 -0
  190. package/src/dtos/run-module-package-seed.dto.ts +12 -0
  191. package/src/helpers/command.service.ts +1 -1
  192. package/src/helpers/module-metadata-helper.service.ts +19 -21
  193. package/src/helpers/module.helper.ts +12 -9
  194. package/src/helpers/typeorm-migration-helpers.ts +163 -0
  195. package/src/index.ts +8 -0
  196. package/src/seeders/module-metadata-seeder.service.ts +63 -38
  197. package/src/seeders/module-test-data.service.ts +1 -1
  198. package/src/seeders/seed-data/solid-core-metadata.json +2365 -1107
  199. package/src/services/crud-helper.service.ts +72 -0
  200. package/src/services/crud.service.ts +11 -104
  201. package/src/services/dashboard-providers/README.md +1 -1
  202. package/src/services/genai/ingest-metadata.service.ts +3 -3
  203. package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +37 -2
  204. package/src/services/mediaStorageProviders/file-storage-provider.ts +5 -1
  205. package/src/services/model-metadata.service.ts +302 -98
  206. package/src/services/module-metadata-explorer.service.ts +670 -0
  207. package/src/services/module-metadata.service.ts +136 -10
  208. package/src/services/module-package.service.ts +1171 -0
  209. package/src/solid-core.module.ts +10 -2
  210. package/.claude/settings.local.json +0 -15
  211. package/CLAUDE.md +0 -26
  212. package/dist/services/database/database-bootstrap.service.d.ts +0 -12
  213. package/dist/services/database/database-bootstrap.service.d.ts.map +0 -1
  214. package/dist/services/database/database-bootstrap.service.js +0 -115
  215. package/dist/services/database/database-bootstrap.service.js.map +0 -1
  216. package/sql/default/mariadb/proc_CleanupModelMetadata.sql +0 -153
  217. package/sql/default/mariadb/proc_CleanupModuleMetadata.sql +0 -56
  218. package/sql/default/mssql/proc_CleanupModuleMetadata.sql +0 -78
  219. package/sql/default/mysql/proc_CleanupModelMetadata.sql +0 -153
  220. package/sql/default/mysql/proc_CleanupModuleMetadata.sql +0 -56
  221. package/sql/default/postgres/proc_CleanupModelMetadata.sql +0 -148
  222. package/sql/default/postgres/proc_CleanupModuleMetadata.sql +0 -50
  223. package/sql/default/postgres/scratchpad.sql.txt +0 -12
  224. package/src/services/1.js +0 -6
  225. package/src/services/database/database-bootstrap.service.ts +0 -91
@@ -749,4 +749,76 @@ export class CrudHelperService {
749
749
  return matchingPermssions.length > 0
750
750
  }
751
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
+
752
824
  }
@@ -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, populateGroup, groupFilter } = basicFilterDto;
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
- const groupByFields = this.crudHelperService.normalize(basicFilterDto.groupBy);
511
- if (!groupByFields.length) {
512
- throw new BadRequestException(ERROR_MESSAGES.INVALID_GROUP_BY_COUNT);
513
- }
514
-
515
- if (basicFilterDto.populateGroup) {
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
- const safeLimit = limit ?? count ?? 0;
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
@@ -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>/<module-name>-metadata.json`
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 = `module-metadata/${enabledModule}/${fileName}`;
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 = `module-metadata/${enabledModule}/genai/${enabledModule}-ingested-info.json`;
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
- throw new Error("Method not implemented.");
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
- await this.fileService.writeStream(this.getFullFilePath(fileName), stream);
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;