@solidxai/core 0.1.11-beta.2 → 0.1.11-beta.4

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 (60) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/dist/controllers/datasource-introspection.controller.d.ts +38 -1
  3. package/dist/controllers/datasource-introspection.controller.d.ts.map +1 -1
  4. package/dist/controllers/datasource-introspection.controller.js +38 -0
  5. package/dist/controllers/datasource-introspection.controller.js.map +1 -1
  6. package/dist/dtos/datasource-introspection-mapping.dto.d.ts +4 -0
  7. package/dist/dtos/datasource-introspection-mapping.dto.d.ts.map +1 -1
  8. package/dist/dtos/datasource-introspection-mapping.dto.js +18 -2
  9. package/dist/dtos/datasource-introspection-mapping.dto.js.map +1 -1
  10. package/dist/entities/{legacy-common-with-id.entity.d.ts → legacy-common-with-generated-id.entity.d.ts} +2 -2
  11. package/dist/entities/legacy-common-with-generated-id.entity.d.ts.map +1 -0
  12. package/dist/entities/{legacy-common-with-id.entity.js → legacy-common-with-generated-id.entity.js} +4 -4
  13. package/dist/entities/legacy-common-with-generated-id.entity.js.map +1 -0
  14. package/dist/entities/{legacy-common.entity.d.ts → legacy-common.entity-with-existing-id.entity.d.ts} +1 -1
  15. package/dist/entities/legacy-common.entity-with-existing-id.entity.d.ts.map +1 -0
  16. package/dist/entities/{legacy-common.entity.js → legacy-common.entity-with-existing-id.entity.js} +1 -1
  17. package/dist/entities/legacy-common.entity-with-existing-id.entity.js.map +1 -0
  18. package/dist/helpers/model-metadata-helper.service.js +3 -3
  19. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  20. package/dist/index.d.ts +2 -2
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +2 -2
  23. package/dist/index.js.map +1 -1
  24. package/dist/interfaces/datasource-introspection-provider.interface.d.ts +1 -0
  25. package/dist/interfaces/datasource-introspection-provider.interface.d.ts.map +1 -1
  26. package/dist/interfaces/datasource-introspection-provider.interface.js.map +1 -1
  27. package/dist/seeders/seed-data/solid-core-metadata.json +12 -3
  28. package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.d.ts.map +1 -1
  29. package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.js +12 -0
  30. package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.js.map +1 -1
  31. package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.d.ts.map +1 -1
  32. package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.js +2 -0
  33. package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.js.map +1 -1
  34. package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.d.ts.map +1 -1
  35. package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.js +28 -15
  36. package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.js.map +1 -1
  37. package/dist/services/datasource-introspection.service.d.ts +52 -2
  38. package/dist/services/datasource-introspection.service.d.ts.map +1 -1
  39. package/dist/services/datasource-introspection.service.js +534 -160
  40. package/dist/services/datasource-introspection.service.js.map +1 -1
  41. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +10 -10
  42. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
  43. package/package.json +1 -1
  44. package/src/controllers/datasource-introspection.controller.ts +27 -1
  45. package/src/dtos/datasource-introspection-mapping.dto.ts +10 -0
  46. package/src/entities/{legacy-common-with-id.entity.ts → legacy-common-with-generated-id.entity.ts} +1 -1
  47. package/src/helpers/model-metadata-helper.service.ts +1 -1
  48. package/src/index.ts +2 -2
  49. package/src/interfaces/datasource-introspection-provider.interface.ts +1 -0
  50. package/src/seeders/seed-data/solid-core-metadata.json +12 -3
  51. package/src/services/datasource-introspection/mssql-datasource-introspection-provider.service.ts +12 -0
  52. package/src/services/datasource-introspection/mysql-datasource-introspection-provider.service.ts +2 -0
  53. package/src/services/datasource-introspection/postgres-datasource-introspection-provider.service.ts +28 -15
  54. package/src/services/datasource-introspection.service.ts +626 -136
  55. package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +2 -2
  56. package/dist/entities/legacy-common-with-id.entity.d.ts.map +0 -1
  57. package/dist/entities/legacy-common-with-id.entity.js.map +0 -1
  58. package/dist/entities/legacy-common.entity.d.ts.map +0 -1
  59. package/dist/entities/legacy-common.entity.js.map +0 -1
  60. /package/src/entities/{legacy-common.entity.ts → legacy-common.entity-with-existing-id.entity.ts} +0 -0
@@ -14,8 +14,8 @@ exports.FileS3StorageProvider = void 0;
14
14
  const common_1 = require("@nestjs/common");
15
15
  const config_1 = require("@nestjs/config");
16
16
  const common_entity_1 = require("../../entities/common.entity");
17
- const legacy_common_entity_1 = require("../../entities/legacy-common.entity");
18
- const legacy_common_with_id_entity_1 = require("../../entities/legacy-common-with-id.entity");
17
+ const legacy_common_entity_with_existing_id_entity_1 = require("../../entities/legacy-common.entity-with-existing-id.entity");
18
+ const legacy_common_with_generated_id_entity_1 = require("../../entities/legacy-common-with-generated-id.entity");
19
19
  const file_1 = require("../file");
20
20
  const media_repository_1 = require("../../repository/media.repository");
21
21
  let FileS3StorageProvider = FileS3StorageProvider_1 = class FileS3StorageProvider {
@@ -28,8 +28,8 @@ let FileS3StorageProvider = FileS3StorageProvider_1 = class FileS3StorageProvide
28
28
  }
29
29
  async storeStreams(streamPairs, entity, mediaFieldMetadata) {
30
30
  const isSupportedEntity = entity instanceof common_entity_1.CommonEntity
31
- || entity instanceof legacy_common_entity_1.LegacyCommonEntityWithExistingId
32
- || entity instanceof legacy_common_with_id_entity_1.LegacyCommonEntityWithGeneratedId;
31
+ || entity instanceof legacy_common_entity_with_existing_id_entity_1.LegacyCommonEntityWithExistingId
32
+ || entity instanceof legacy_common_with_generated_id_entity_1.LegacyCommonEntityWithGeneratedId;
33
33
  if (!isSupportedEntity) {
34
34
  throw new Error("Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId");
35
35
  }
@@ -60,8 +60,8 @@ let FileS3StorageProvider = FileS3StorageProvider_1 = class FileS3StorageProvide
60
60
  }
61
61
  async retrieve(entity, mediaFieldMetadata) {
62
62
  const isSupportedEntity = entity instanceof common_entity_1.CommonEntity
63
- || entity instanceof legacy_common_entity_1.LegacyCommonEntityWithExistingId
64
- || entity instanceof legacy_common_with_id_entity_1.LegacyCommonEntityWithGeneratedId;
63
+ || entity instanceof legacy_common_entity_with_existing_id_entity_1.LegacyCommonEntityWithExistingId
64
+ || entity instanceof legacy_common_with_generated_id_entity_1.LegacyCommonEntityWithGeneratedId;
65
65
  if (!isSupportedEntity) {
66
66
  throw new Error("Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId");
67
67
  }
@@ -81,8 +81,8 @@ let FileS3StorageProvider = FileS3StorageProvider_1 = class FileS3StorageProvide
81
81
  }
82
82
  async store(files, entity, mediaFieldMetadata) {
83
83
  const isSupportedEntity = entity instanceof common_entity_1.CommonEntity
84
- || entity instanceof legacy_common_entity_1.LegacyCommonEntityWithExistingId
85
- || entity instanceof legacy_common_with_id_entity_1.LegacyCommonEntityWithGeneratedId;
84
+ || entity instanceof legacy_common_entity_with_existing_id_entity_1.LegacyCommonEntityWithExistingId
85
+ || entity instanceof legacy_common_with_generated_id_entity_1.LegacyCommonEntityWithGeneratedId;
86
86
  if (!isSupportedEntity) {
87
87
  throw new Error("Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId");
88
88
  }
@@ -114,8 +114,8 @@ let FileS3StorageProvider = FileS3StorageProvider_1 = class FileS3StorageProvide
114
114
  }
115
115
  async delete(entity, mediaFieldMetadata) {
116
116
  const isSupportedEntity = entity instanceof common_entity_1.CommonEntity
117
- || entity instanceof legacy_common_entity_1.LegacyCommonEntityWithExistingId
118
- || entity instanceof legacy_common_with_id_entity_1.LegacyCommonEntityWithGeneratedId;
117
+ || entity instanceof legacy_common_entity_with_existing_id_entity_1.LegacyCommonEntityWithExistingId
118
+ || entity instanceof legacy_common_with_generated_id_entity_1.LegacyCommonEntityWithGeneratedId;
119
119
  if (!isSupportedEntity) {
120
120
  throw new Error("Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId");
121
121
  }
@@ -1 +1 @@
1
- {"version":3,"file":"file-s3-storage-provider.js","sourceRoot":"","sources":["../../../src/services/mediaStorageProviders/file-s3-storage-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from \"@nestjs/common\";\nimport { ConfigService } from \"@nestjs/config\";\nimport { CommonEntity } from \"src/entities/common.entity\";\nimport { FieldMetadata } from \"src/entities/field-metadata.entity\";\nimport { LegacyCommonEntityWithExistingId } from \"src/entities/legacy-common.entity\";\nimport { LegacyCommonEntityWithGeneratedId } from \"src/entities/legacy-common-with-id.entity\";\nimport { Media } from \"src/entities/media.entity\";\nimport { MediaStorageProvider } from \"src/interfaces\";\nimport { DiskFileService, S3FileService } from \"src/services/file\";\nimport { Readable } from \"stream\";\nimport { MediaRepository } from \"src/repository/media.repository\";\n\n@Injectable()\nexport class FileS3StorageProvider<T> implements MediaStorageProvider<T> {\n private logger = new Logger(FileS3StorageProvider.name);\n\n constructor(\n private readonly configService: ConfigService,\n readonly diskFileService: DiskFileService,\n readonly s3FileService: S3FileService,\n readonly mediaRepository: MediaRepository,\n ) { }\n\n async storeStreams(streamPairs: [Readable, string][], entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]> {\n const isSupportedEntity = entity instanceof CommonEntity\n || entity instanceof LegacyCommonEntityWithExistingId\n || entity instanceof LegacyCommonEntityWithGeneratedId;\n if (!isSupportedEntity) {\n throw new Error(\"Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId\");\n }\n const result: Media[] = [];\n const storageProvider = mediaFieldMetadata.mediaStorageProvider;\n const region = this.getEffectiveRegion(storageProvider.region);\n\n for (const [stream, fileName] of streamPairs) {\n const bucketName = storageProvider.bucketName;\n\n // Buffer the stream so we can get the byte count and upload in one pass\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n const fileData = Buffer.concat(chunks);\n const fileSize = fileData.length;\n\n await this.s3FileService.write(`${bucketName}:${fileName}`, fileData, { region });\n\n const mediaEntity = await this.mediaRepository.createMedia({\n // @ts-ignore\n entityId: entity.id,\n modelMetadataId: mediaFieldMetadata.model.id,\n relativeUri: fileName,\n fileSize,\n mediaStorageProviderMetadataId: mediaFieldMetadata.mediaStorageProvider.id,\n fieldMetadataId: mediaFieldMetadata.id\n }) as unknown as Media;\n result.push(mediaEntity);\n this.logger.debug(`Stored media with`, mediaEntity);\n }\n return result;\n }\n\n async retrieve(entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]> {\n const isSupportedEntity = entity instanceof CommonEntity\n || entity instanceof LegacyCommonEntityWithExistingId\n || entity instanceof LegacyCommonEntityWithGeneratedId;\n if (!isSupportedEntity) {\n throw new Error(\"Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId\"); // FIXME This needs to be handled through generics. e.g T extends CommonEntity\n }\n // @ts-ignore\n const media = await this.mediaRepository.findByEntityIdAndFieldIdAndModelMetadataId(entity.id, mediaFieldMetadata.id, mediaFieldMetadata.model.id, ['mediaStorageProviderMetadata']);\n\n // TODO: Check if the mediaStorageProvider (s3 in this case) is configured with a public bucket or not.\n // If private bucket then we need to return a \"signed-url\", the timeout for the signed url can be configured in the media storage provider entity and modified using the CRUD interface.\n // Add the full URL to the media\n for (const m of media) {\n const storageMeta = m.mediaStorageProviderMetadata;\n const region = this.getEffectiveRegion(storageMeta.region);\n if (storageMeta.isPublic === false) {\n // Generate signed URL\n const expiryInSeconds = (storageMeta.signedUrlExpiry ?? 60) * 60;\n m['_full_url'] = await this.s3FileService.getUrl(`${storageMeta?.bucketName}:${m.relativeUri}`, { expiresIn: expiryInSeconds, region });\n } else {\n // Public S3 or local filesystem: use normal URL\n m['_full_url'] = this.getFullFilePath(m);\n }\n }\n\n return media;\n // media.forEach(m => {\n // m['_full_url'] = this.getFullFilePath(m);\n // });\n // return media;\n }\n\n async store(files: Express.Multer.File[], entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]> {\n const isSupportedEntity = entity instanceof CommonEntity\n || entity instanceof LegacyCommonEntityWithExistingId\n || entity instanceof LegacyCommonEntityWithGeneratedId;\n if (!isSupportedEntity) {\n throw new Error(\"Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId\"); // FIXME This needs to be handled through generics. e.g T extends CommonEntity\n }\n const result: Media[] = [];\n const storageProvider = mediaFieldMetadata.mediaStorageProvider;\n const region = this.getEffectiveRegion(storageProvider.region);\n\n for (const file of files) {\n const fileName = this.getFileName(file);\n const bucketName = storageProvider.bucketName;\n\n // Read file from disk and upload to S3\n const fileData = await this.diskFileService.read(file.path);\n await this.s3FileService.write(`${bucketName}:${fileName}`, fileData, { contentType: file.mimetype, region });\n\n // Delete temp file from disk\n await this.diskFileService.delete(file.path);\n\n const awsFileUrl = fileName;\n\n // Create an entry in the media table\n const mediaEntity = await this.mediaRepository.createMedia({\n // @ts-ignore\n entityId: entity.id,\n modelMetadataId: mediaFieldMetadata.model.id,\n relativeUri: awsFileUrl,\n mimeType: file.mimetype,\n fileSize: file.size,\n originalFileName: file.originalname,\n mediaStorageProviderMetadataId: mediaFieldMetadata.mediaStorageProvider.id,\n fieldMetadataId: mediaFieldMetadata.id\n }) as unknown as Media;\n result.push(mediaEntity);\n this.logger.debug(`Stored media with`, mediaEntity);\n };\n return result;\n }\n\n async delete(entity: T, mediaFieldMetadata: FieldMetadata): Promise<void> {\n const isSupportedEntity = entity instanceof CommonEntity\n || entity instanceof LegacyCommonEntityWithExistingId\n || entity instanceof LegacyCommonEntityWithGeneratedId;\n if (!isSupportedEntity) {\n throw new Error(\"Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId\"); // FIXME This needs to be handled through generics. e.g T extends CommonEntity\n }\n const storageProvider = mediaFieldMetadata.mediaStorageProvider;\n const region = this.getEffectiveRegion(storageProvider.region);\n\n // @ts-ignore\n const existingMedia = await this.mediaRepository.findByEntityIdAndFieldIdAndModelMetadataId(entity.id, mediaFieldMetadata.id, mediaFieldMetadata.model.id, ['mediaStorageProviderMetadata']);\n // @ts-ignore\n this.mediaRepository.deleteByEntityIdAndFieldIdAndModelMetadataId(entity.id, mediaFieldMetadata.id, mediaFieldMetadata.model.id);\n for (const media of existingMedia) {\n const bucketName = storageProvider.bucketName;\n await this.s3FileService.delete(`${bucketName}:${media.relativeUri}`, { region });\n }\n }\n\n async deleteByMediaRecord(media: Media): Promise<void> {\n const storageProvider = media?.mediaStorageProviderMetadata;\n if (!storageProvider) {\n throw new Error(`mediaStorageProviderMetadata is not populated for media id ${media?.id ?? 'unknown'}`);\n }\n if (!storageProvider?.bucketName || !media?.relativeUri) {\n return;\n }\n const region = this.getEffectiveRegion(storageProvider.region);\n await this.s3FileService.delete(`${storageProvider.bucketName}:${media.relativeUri}`, { region });\n }\n\n /**\n * Get the effective region to use for S3 operations.\n * Uses the provider-specific region if configured, otherwise falls back to env variable.\n */\n private getEffectiveRegion(providerRegion?: string): string | undefined {\n return providerRegion || this.configService.get('S3_AWS_REGION_NAME');\n }\n\n private getFullFilePath(media: Media): string {\n // Use provider region if available, fallback to env variable\n const region = this.getEffectiveRegion(media.mediaStorageProviderMetadata.region);\n // https://lunarismedia.s3.ap-south-1.amazonaws.com/LUNARIS_CP_REGISTRATION_CREATIVE.jpg\n return `https://${media.mediaStorageProviderMetadata.bucketName}.s3.${region}.amazonaws.com/${media.relativeUri}`;\n }\n\n private getFileName(file: Express.Multer.File): string {\n return `${file.filename}-${file.originalname}`;\n }\n}\n"]}
1
+ {"version":3,"file":"file-s3-storage-provider.js","sourceRoot":"","sources":["../../../src/services/mediaStorageProviders/file-s3-storage-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from \"@nestjs/common\";\nimport { ConfigService } from \"@nestjs/config\";\nimport { CommonEntity } from \"src/entities/common.entity\";\nimport { FieldMetadata } from \"src/entities/field-metadata.entity\";\nimport { LegacyCommonEntityWithExistingId } from \"src/entities/legacy-common.entity-with-existing-id.entity\";\nimport { LegacyCommonEntityWithGeneratedId } from \"src/entities/legacy-common-with-generated-id.entity\";\nimport { Media } from \"src/entities/media.entity\";\nimport { MediaStorageProvider } from \"src/interfaces\";\nimport { DiskFileService, S3FileService } from \"src/services/file\";\nimport { Readable } from \"stream\";\nimport { MediaRepository } from \"src/repository/media.repository\";\n\n@Injectable()\nexport class FileS3StorageProvider<T> implements MediaStorageProvider<T> {\n private logger = new Logger(FileS3StorageProvider.name);\n\n constructor(\n private readonly configService: ConfigService,\n readonly diskFileService: DiskFileService,\n readonly s3FileService: S3FileService,\n readonly mediaRepository: MediaRepository,\n ) { }\n\n async storeStreams(streamPairs: [Readable, string][], entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]> {\n const isSupportedEntity = entity instanceof CommonEntity\n || entity instanceof LegacyCommonEntityWithExistingId\n || entity instanceof LegacyCommonEntityWithGeneratedId;\n if (!isSupportedEntity) {\n throw new Error(\"Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId\");\n }\n const result: Media[] = [];\n const storageProvider = mediaFieldMetadata.mediaStorageProvider;\n const region = this.getEffectiveRegion(storageProvider.region);\n\n for (const [stream, fileName] of streamPairs) {\n const bucketName = storageProvider.bucketName;\n\n // Buffer the stream so we can get the byte count and upload in one pass\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n const fileData = Buffer.concat(chunks);\n const fileSize = fileData.length;\n\n await this.s3FileService.write(`${bucketName}:${fileName}`, fileData, { region });\n\n const mediaEntity = await this.mediaRepository.createMedia({\n // @ts-ignore\n entityId: entity.id,\n modelMetadataId: mediaFieldMetadata.model.id,\n relativeUri: fileName,\n fileSize,\n mediaStorageProviderMetadataId: mediaFieldMetadata.mediaStorageProvider.id,\n fieldMetadataId: mediaFieldMetadata.id\n }) as unknown as Media;\n result.push(mediaEntity);\n this.logger.debug(`Stored media with`, mediaEntity);\n }\n return result;\n }\n\n async retrieve(entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]> {\n const isSupportedEntity = entity instanceof CommonEntity\n || entity instanceof LegacyCommonEntityWithExistingId\n || entity instanceof LegacyCommonEntityWithGeneratedId;\n if (!isSupportedEntity) {\n throw new Error(\"Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId\"); // FIXME This needs to be handled through generics. e.g T extends CommonEntity\n }\n // @ts-ignore\n const media = await this.mediaRepository.findByEntityIdAndFieldIdAndModelMetadataId(entity.id, mediaFieldMetadata.id, mediaFieldMetadata.model.id, ['mediaStorageProviderMetadata']);\n\n // TODO: Check if the mediaStorageProvider (s3 in this case) is configured with a public bucket or not.\n // If private bucket then we need to return a \"signed-url\", the timeout for the signed url can be configured in the media storage provider entity and modified using the CRUD interface.\n // Add the full URL to the media\n for (const m of media) {\n const storageMeta = m.mediaStorageProviderMetadata;\n const region = this.getEffectiveRegion(storageMeta.region);\n if (storageMeta.isPublic === false) {\n // Generate signed URL\n const expiryInSeconds = (storageMeta.signedUrlExpiry ?? 60) * 60;\n m['_full_url'] = await this.s3FileService.getUrl(`${storageMeta?.bucketName}:${m.relativeUri}`, { expiresIn: expiryInSeconds, region });\n } else {\n // Public S3 or local filesystem: use normal URL\n m['_full_url'] = this.getFullFilePath(m);\n }\n }\n\n return media;\n // media.forEach(m => {\n // m['_full_url'] = this.getFullFilePath(m);\n // });\n // return media;\n }\n\n async store(files: Express.Multer.File[], entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]> {\n const isSupportedEntity = entity instanceof CommonEntity\n || entity instanceof LegacyCommonEntityWithExistingId\n || entity instanceof LegacyCommonEntityWithGeneratedId;\n if (!isSupportedEntity) {\n throw new Error(\"Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId\"); // FIXME This needs to be handled through generics. e.g T extends CommonEntity\n }\n const result: Media[] = [];\n const storageProvider = mediaFieldMetadata.mediaStorageProvider;\n const region = this.getEffectiveRegion(storageProvider.region);\n\n for (const file of files) {\n const fileName = this.getFileName(file);\n const bucketName = storageProvider.bucketName;\n\n // Read file from disk and upload to S3\n const fileData = await this.diskFileService.read(file.path);\n await this.s3FileService.write(`${bucketName}:${fileName}`, fileData, { contentType: file.mimetype, region });\n\n // Delete temp file from disk\n await this.diskFileService.delete(file.path);\n\n const awsFileUrl = fileName;\n\n // Create an entry in the media table\n const mediaEntity = await this.mediaRepository.createMedia({\n // @ts-ignore\n entityId: entity.id,\n modelMetadataId: mediaFieldMetadata.model.id,\n relativeUri: awsFileUrl,\n mimeType: file.mimetype,\n fileSize: file.size,\n originalFileName: file.originalname,\n mediaStorageProviderMetadataId: mediaFieldMetadata.mediaStorageProvider.id,\n fieldMetadataId: mediaFieldMetadata.id\n }) as unknown as Media;\n result.push(mediaEntity);\n this.logger.debug(`Stored media with`, mediaEntity);\n };\n return result;\n }\n\n async delete(entity: T, mediaFieldMetadata: FieldMetadata): Promise<void> {\n const isSupportedEntity = entity instanceof CommonEntity\n || entity instanceof LegacyCommonEntityWithExistingId\n || entity instanceof LegacyCommonEntityWithGeneratedId;\n if (!isSupportedEntity) {\n throw new Error(\"Entity must be an instance of CommonEntity, LegacyCommonEntityWithExistingId or LegacyCommonEntityWithGeneratedId\"); // FIXME This needs to be handled through generics. e.g T extends CommonEntity\n }\n const storageProvider = mediaFieldMetadata.mediaStorageProvider;\n const region = this.getEffectiveRegion(storageProvider.region);\n\n // @ts-ignore\n const existingMedia = await this.mediaRepository.findByEntityIdAndFieldIdAndModelMetadataId(entity.id, mediaFieldMetadata.id, mediaFieldMetadata.model.id, ['mediaStorageProviderMetadata']);\n // @ts-ignore\n this.mediaRepository.deleteByEntityIdAndFieldIdAndModelMetadataId(entity.id, mediaFieldMetadata.id, mediaFieldMetadata.model.id);\n for (const media of existingMedia) {\n const bucketName = storageProvider.bucketName;\n await this.s3FileService.delete(`${bucketName}:${media.relativeUri}`, { region });\n }\n }\n\n async deleteByMediaRecord(media: Media): Promise<void> {\n const storageProvider = media?.mediaStorageProviderMetadata;\n if (!storageProvider) {\n throw new Error(`mediaStorageProviderMetadata is not populated for media id ${media?.id ?? 'unknown'}`);\n }\n if (!storageProvider?.bucketName || !media?.relativeUri) {\n return;\n }\n const region = this.getEffectiveRegion(storageProvider.region);\n await this.s3FileService.delete(`${storageProvider.bucketName}:${media.relativeUri}`, { region });\n }\n\n /**\n * Get the effective region to use for S3 operations.\n * Uses the provider-specific region if configured, otherwise falls back to env variable.\n */\n private getEffectiveRegion(providerRegion?: string): string | undefined {\n return providerRegion || this.configService.get('S3_AWS_REGION_NAME');\n }\n\n private getFullFilePath(media: Media): string {\n // Use provider region if available, fallback to env variable\n const region = this.getEffectiveRegion(media.mediaStorageProviderMetadata.region);\n // https://lunarismedia.s3.ap-south-1.amazonaws.com/LUNARIS_CP_REGISTRATION_CREATIVE.jpg\n return `https://${media.mediaStorageProviderMetadata.bucketName}.s3.${region}.amazonaws.com/${media.relativeUri}`;\n }\n\n private getFileName(file: Express.Multer.File): string {\n return `${file.filename}-${file.originalname}`;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidxai/core",
3
- "version": "0.1.11-beta.2",
3
+ "version": "0.1.11-beta.4",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,6 +1,6 @@
1
1
  import { Body, Controller, Get, Param, ParseIntPipe, Post, Query } from "@nestjs/common";
2
2
  import { ApiBearerAuth, ApiTags } from "@nestjs/swagger";
3
- import { DatasourceIntrospectionMappingDto } from "../dtos/datasource-introspection-mapping.dto";
3
+ import { DatasourceIntrospectionMappingDto, DatasourceIntrospectionRunMigrationDto } from "../dtos/datasource-introspection-mapping.dto";
4
4
  import { DatasourceIntrospectionService } from "../services/datasource-introspection.service";
5
5
 
6
6
  @Controller("datasource-introspection")
@@ -55,4 +55,30 @@ export class DatasourceIntrospectionController {
55
55
  ) {
56
56
  return this.datasourceIntrospectionService.applyMapping(moduleId, mappingDto);
57
57
  }
58
+
59
+ @ApiBearerAuth("jwt")
60
+ @Post("modules/:moduleId/create-migration-artifacts")
61
+ createMigrationArtifacts(
62
+ @Param("moduleId", ParseIntPipe) moduleId: number,
63
+ @Body() mappingDto: DatasourceIntrospectionMappingDto,
64
+ ) {
65
+ return this.datasourceIntrospectionService.createMigrationArtifacts(moduleId, mappingDto);
66
+ }
67
+
68
+ @ApiBearerAuth("jwt")
69
+ @Post("modules/:moduleId/generate-code")
70
+ generateCode(
71
+ @Param("moduleId", ParseIntPipe) moduleId: number,
72
+ ) {
73
+ return this.datasourceIntrospectionService.generateCode(moduleId);
74
+ }
75
+
76
+ @ApiBearerAuth("jwt")
77
+ @Post("modules/:moduleId/run-migration")
78
+ runMigration(
79
+ @Param("moduleId", ParseIntPipe) moduleId: number,
80
+ @Body() payload: DatasourceIntrospectionRunMigrationDto,
81
+ ) {
82
+ return this.datasourceIntrospectionService.runMigration(moduleId, payload.datasource);
83
+ }
58
84
  }
@@ -22,6 +22,10 @@ export class DatasourceIntrospectionMappingColumnDto {
22
22
  @IsString()
23
23
  fieldName: string;
24
24
 
25
+ @ApiProperty()
26
+ @IsString()
27
+ displayName: string;
28
+
25
29
  @ApiProperty()
26
30
  @IsString()
27
31
  dataType: string;
@@ -180,3 +184,9 @@ export class DatasourceIntrospectionMappingDto {
180
184
  @IsObject()
181
185
  reviewedModel?: Record<string, any>;
182
186
  }
187
+
188
+ export class DatasourceIntrospectionRunMigrationDto {
189
+ @ApiProperty()
190
+ @IsString()
191
+ datasource: string;
192
+ }
@@ -1,6 +1,6 @@
1
1
  import { Exclude, Expose } from "class-transformer";
2
2
  import { Column, Generated } from "typeorm";
3
- import { LEGACY_TABLE_FIELDS_PREFIX, LegacyCommonEntityWithExistingId } from "./legacy-common.entity";
3
+ import { LEGACY_TABLE_FIELDS_PREFIX, LegacyCommonEntityWithExistingId } from "./legacy-common.entity-with-existing-id.entity";
4
4
 
5
5
  @Exclude()
6
6
  export abstract class LegacyCommonEntityWithGeneratedId extends LegacyCommonEntityWithExistingId {
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { forwardRef, Inject, Injectable, Logger } from "@nestjs/common";
4
4
  import { _ } from "lodash";
5
- import { LEGACY_TABLE_FIELDS_PREFIX } from "src/entities/legacy-common.entity";
5
+ import { LEGACY_TABLE_FIELDS_PREFIX } from "src/entities/legacy-common.entity-with-existing-id.entity";
6
6
  import { LegacyTableType } from "src/enums/legacy-table-type.enum";
7
7
  import { ModelMetadataRepository } from "src/repository/model-metadata.repository";
8
8
  import { SolidRegistry } from "./solid-registry";
package/src/index.ts CHANGED
@@ -119,8 +119,8 @@ export * from './dtos/update-dashboard-user-layout.dto'
119
119
 
120
120
  export * from './entities/action-metadata.entity'
121
121
  export * from './entities/common.entity'
122
- export * from './entities/legacy-common.entity'
123
- export * from './entities/legacy-common-with-id.entity'
122
+ export * from './entities/legacy-common.entity-with-existing-id.entity'
123
+ export * from './entities/legacy-common-with-generated-id.entity'
124
124
  export * from './entities/email-attachment.entity'
125
125
  export * from './entities/email-template.entity'
126
126
  export * from './entities/field-metadata.entity'
@@ -11,6 +11,7 @@ export type DatasourceIntrospectionColumn = {
11
11
  columnName: string;
12
12
  dataType: string;
13
13
  isAutoGenerated: boolean;
14
+ isPrimaryKey: boolean;
14
15
  isNullable: boolean;
15
16
  defaultValue: string | null;
16
17
  characterMaximumLength: number | null;
@@ -1077,15 +1077,24 @@
1077
1077
  {
1078
1078
  "name": "type",
1079
1079
  "displayName": "Type",
1080
- "type": "shortText",
1080
+ "type": "selectionStatic",
1081
1081
  "ormType": "varchar",
1082
+ "length": 256,
1082
1083
  "required": true,
1083
1084
  "unique": false,
1084
1085
  "index": true,
1085
1086
  "private": false,
1086
1087
  "encrypt": false,
1087
1088
  "columnName": "type",
1088
- "isSystem": true
1089
+ "isSystem": true,
1090
+ "selectionValueType": "string",
1091
+ "selectionStaticValues": [
1092
+ "list:List",
1093
+ "form:Form",
1094
+ "tree:Tree",
1095
+ "kanban:Kanban",
1096
+ "card:Card"
1097
+ ]
1089
1098
  },
1090
1099
  {
1091
1100
  "name": "context",
@@ -1584,7 +1593,7 @@
1584
1593
  "name": "roles",
1585
1594
  "displayName": "Roles",
1586
1595
  "type": "relation",
1587
- "required": true,
1596
+ "required": false,
1588
1597
  "unique": false,
1589
1598
  "index": true,
1590
1599
  "private": false,
@@ -39,6 +39,7 @@ export class MssqlDatasourceIntrospectionProviderService implements DatasourceIn
39
39
  c.name AS columnName,
40
40
  ty.name AS dataType,
41
41
  c.is_identity AS isAutoGenerated,
42
+ CASE WHEN pk.column_id IS NOT NULL THEN 1 ELSE 0 END AS isPrimaryKey,
42
43
  CASE WHEN c.is_nullable = 1 THEN 'YES' ELSE 'NO' END AS isNullable,
43
44
  dc.definition AS defaultValue,
44
45
  CASE
@@ -52,6 +53,16 @@ export class MssqlDatasourceIntrospectionProviderService implements DatasourceIn
52
53
  INNER JOIN sys.columns c ON c.object_id = t.object_id
53
54
  INNER JOIN sys.types ty ON ty.user_type_id = c.user_type_id
54
55
  LEFT JOIN sys.default_constraints dc ON dc.object_id = c.default_object_id
56
+ LEFT JOIN (
57
+ SELECT ic.object_id, ic.column_id
58
+ FROM sys.index_columns ic
59
+ INNER JOIN sys.key_constraints kc
60
+ ON kc.parent_object_id = ic.object_id
61
+ AND kc.unique_index_id = ic.index_id
62
+ WHERE kc.type = 'PK'
63
+ ) pk
64
+ ON pk.object_id = c.object_id
65
+ AND pk.column_id = c.column_id
55
66
  WHERE schema_name(t.schema_id) NOT IN ('sys', 'INFORMATION_SCHEMA')
56
67
  ORDER BY schema_name(t.schema_id), t.name, c.column_id
57
68
  `);
@@ -62,6 +73,7 @@ export class MssqlDatasourceIntrospectionProviderService implements DatasourceIn
62
73
  columnName: row.columnName,
63
74
  dataType: row.dataType,
64
75
  isAutoGenerated: Boolean(row.isAutoGenerated),
76
+ isPrimaryKey: Boolean(row.isPrimaryKey),
65
77
  isNullable: String(row.isNullable).toUpperCase() === "YES",
66
78
  defaultValue: row.defaultValue ?? null,
67
79
  characterMaximumLength: this.toNumberOrNull(row.characterMaximumLength),
@@ -39,6 +39,7 @@ export class MysqlDatasourceIntrospectionProviderService implements DatasourceIn
39
39
  COLUMN_NAME AS columnName,
40
40
  DATA_TYPE AS dataType,
41
41
  EXTRA AS extra,
42
+ COLUMN_KEY AS columnKey,
42
43
  IS_NULLABLE AS isNullable,
43
44
  COLUMN_DEFAULT AS defaultValue,
44
45
  CHARACTER_MAXIMUM_LENGTH AS characterMaximumLength,
@@ -56,6 +57,7 @@ export class MysqlDatasourceIntrospectionProviderService implements DatasourceIn
56
57
  columnName: row.columnName,
57
58
  dataType: row.dataType,
58
59
  isAutoGenerated: String(row.extra ?? "").toLowerCase().includes("auto_increment"),
60
+ isPrimaryKey: String(row.columnKey ?? "").toUpperCase() === "PRI",
59
61
  isNullable: String(row.isNullable).toUpperCase() === "YES",
60
62
  defaultValue: row.defaultValue ?? null,
61
63
  characterMaximumLength: this.toNumberOrNull(row.characterMaximumLength),
@@ -34,24 +34,36 @@ export class PostgresDatasourceIntrospectionProviderService implements Datasourc
34
34
  async listColumns(dataSource: DataSource): Promise<DatasourceIntrospectionColumn[]> {
35
35
  const rows = await dataSource.query(`
36
36
  SELECT
37
- TABLE_SCHEMA AS "tableSchema",
38
- TABLE_NAME AS "tableName",
39
- COLUMN_NAME AS "columnName",
40
- DATA_TYPE AS "dataType",
37
+ c.TABLE_SCHEMA AS "tableSchema",
38
+ c.TABLE_NAME AS "tableName",
39
+ c.COLUMN_NAME AS "columnName",
40
+ c.DATA_TYPE AS "dataType",
41
41
  CASE
42
- WHEN is_identity = 'YES' THEN true
43
- WHEN COLUMN_DEFAULT LIKE 'nextval(%' THEN true
42
+ WHEN c.is_identity = 'YES' THEN true
43
+ WHEN c.COLUMN_DEFAULT LIKE 'nextval(%' THEN true
44
44
  ELSE false
45
45
  END AS "isAutoGenerated",
46
- IS_NULLABLE AS "isNullable",
47
- COLUMN_DEFAULT AS "defaultValue",
48
- CHARACTER_MAXIMUM_LENGTH AS "characterMaximumLength",
49
- NUMERIC_PRECISION AS "numericPrecision",
50
- NUMERIC_SCALE AS "numericScale",
51
- ORDINAL_POSITION AS "ordinalPosition"
52
- FROM INFORMATION_SCHEMA.COLUMNS
53
- WHERE TABLE_SCHEMA NOT IN ('pg_catalog', 'information_schema')
54
- ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION
46
+ EXISTS (
47
+ SELECT 1
48
+ FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
49
+ INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
50
+ ON kcu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
51
+ AND kcu.TABLE_SCHEMA = tc.TABLE_SCHEMA
52
+ AND kcu.TABLE_NAME = tc.TABLE_NAME
53
+ WHERE tc.CONSTRAINT_TYPE = 'PRIMARY KEY'
54
+ AND tc.TABLE_SCHEMA = c.TABLE_SCHEMA
55
+ AND tc.TABLE_NAME = c.TABLE_NAME
56
+ AND kcu.COLUMN_NAME = c.COLUMN_NAME
57
+ ) AS "isPrimaryKey",
58
+ c.IS_NULLABLE AS "isNullable",
59
+ c.COLUMN_DEFAULT AS "defaultValue",
60
+ c.CHARACTER_MAXIMUM_LENGTH AS "characterMaximumLength",
61
+ c.NUMERIC_PRECISION AS "numericPrecision",
62
+ c.NUMERIC_SCALE AS "numericScale",
63
+ c.ORDINAL_POSITION AS "ordinalPosition"
64
+ FROM INFORMATION_SCHEMA.COLUMNS c
65
+ WHERE c.TABLE_SCHEMA NOT IN ('pg_catalog', 'information_schema')
66
+ ORDER BY c.TABLE_SCHEMA, c.TABLE_NAME, c.ORDINAL_POSITION
55
67
  `);
56
68
 
57
69
  return rows.map((row: any) => ({
@@ -60,6 +72,7 @@ export class PostgresDatasourceIntrospectionProviderService implements Datasourc
60
72
  columnName: row.columnName,
61
73
  dataType: row.dataType,
62
74
  isAutoGenerated: Boolean(row.isAutoGenerated),
75
+ isPrimaryKey: Boolean(row.isPrimaryKey),
63
76
  isNullable: String(row.isNullable).toUpperCase() === "YES",
64
77
  defaultValue: row.defaultValue ?? null,
65
78
  characterMaximumLength: this.toNumberOrNull(row.characterMaximumLength),