@friggframework/core 2.0.0-next.5 → 2.0.0-next.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +693 -0
- package/README.md +959 -50
- package/application/commands/README.md +421 -0
- package/application/commands/credential-commands.js +224 -0
- package/application/commands/entity-commands.js +315 -0
- package/application/commands/integration-commands.js +179 -0
- package/application/commands/user-commands.js +213 -0
- package/application/index.js +69 -0
- package/core/CLAUDE.md +690 -0
- package/core/Worker.js +8 -21
- package/core/create-handler.js +2 -7
- package/credential/repositories/credential-repository-factory.js +47 -0
- package/credential/repositories/credential-repository-interface.js +98 -0
- package/credential/repositories/credential-repository-mongo.js +307 -0
- package/credential/repositories/credential-repository-postgres.js +313 -0
- package/credential/repositories/credential-repository.js +302 -0
- package/credential/use-cases/get-credential-for-user.js +21 -0
- package/credential/use-cases/update-authentication-status.js +15 -0
- package/database/MONGODB_TRANSACTION_FIX.md +198 -0
- package/database/adapters/lambda-invoker.js +97 -0
- package/database/config.js +154 -0
- package/database/encryption/README.md +684 -0
- package/database/encryption/encryption-schema-registry.js +141 -0
- package/database/encryption/field-encryption-service.js +226 -0
- package/database/encryption/logger.js +79 -0
- package/database/encryption/prisma-encryption-extension.js +222 -0
- package/database/index.js +25 -12
- package/database/models/WebsocketConnection.js +16 -10
- package/database/models/readme.md +1 -0
- package/database/prisma.js +222 -0
- package/database/repositories/health-check-repository-factory.js +43 -0
- package/database/repositories/health-check-repository-interface.js +87 -0
- package/database/repositories/health-check-repository-mongodb.js +91 -0
- package/database/repositories/health-check-repository-postgres.js +82 -0
- package/database/repositories/health-check-repository.js +108 -0
- package/database/repositories/migration-status-repository-s3.js +137 -0
- package/database/use-cases/check-database-health-use-case.js +29 -0
- package/database/use-cases/check-database-state-use-case.js +81 -0
- package/database/use-cases/check-encryption-health-use-case.js +83 -0
- package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
- package/database/use-cases/get-migration-status-use-case.js +93 -0
- package/database/use-cases/run-database-migration-use-case.js +137 -0
- package/database/use-cases/test-encryption-use-case.js +253 -0
- package/database/use-cases/trigger-database-migration-use-case.js +157 -0
- package/database/utils/mongodb-collection-utils.js +91 -0
- package/database/utils/mongodb-schema-init.js +106 -0
- package/database/utils/prisma-runner.js +400 -0
- package/database/utils/prisma-schema-parser.js +182 -0
- package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
- package/encrypt/Cryptor.js +34 -168
- package/encrypt/index.js +1 -2
- package/encrypt/test-encrypt.js +0 -2
- package/generated/prisma-mongodb/client.d.ts +1 -0
- package/generated/prisma-mongodb/client.js +4 -0
- package/generated/prisma-mongodb/default.d.ts +1 -0
- package/generated/prisma-mongodb/default.js +4 -0
- package/generated/prisma-mongodb/edge.d.ts +1 -0
- package/generated/prisma-mongodb/edge.js +334 -0
- package/generated/prisma-mongodb/index-browser.js +316 -0
- package/generated/prisma-mongodb/index.d.ts +22898 -0
- package/generated/prisma-mongodb/index.js +359 -0
- package/generated/prisma-mongodb/package.json +183 -0
- package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
- package/generated/prisma-mongodb/runtime/binary.js +289 -0
- package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
- package/generated/prisma-mongodb/runtime/edge.js +34 -0
- package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
- package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
- package/generated/prisma-mongodb/runtime/react-native.js +83 -0
- package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-mongodb/schema.prisma +362 -0
- package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm.d.ts +1 -0
- package/generated/prisma-mongodb/wasm.js +341 -0
- package/generated/prisma-postgresql/client.d.ts +1 -0
- package/generated/prisma-postgresql/client.js +4 -0
- package/generated/prisma-postgresql/default.d.ts +1 -0
- package/generated/prisma-postgresql/default.js +4 -0
- package/generated/prisma-postgresql/edge.d.ts +1 -0
- package/generated/prisma-postgresql/edge.js +356 -0
- package/generated/prisma-postgresql/index-browser.js +338 -0
- package/generated/prisma-postgresql/index.d.ts +25072 -0
- package/generated/prisma-postgresql/index.js +381 -0
- package/generated/prisma-postgresql/package.json +183 -0
- package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query_engine_bg.js +2 -0
- package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
- package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
- package/generated/prisma-postgresql/runtime/binary.js +289 -0
- package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
- package/generated/prisma-postgresql/runtime/edge.js +34 -0
- package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
- package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
- package/generated/prisma-postgresql/runtime/react-native.js +83 -0
- package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-postgresql/schema.prisma +345 -0
- package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm.d.ts +1 -0
- package/generated/prisma-postgresql/wasm.js +363 -0
- package/handlers/WEBHOOKS.md +653 -0
- package/handlers/app-definition-loader.js +38 -0
- package/handlers/app-handler-helpers.js +56 -0
- package/handlers/backend-utils.js +180 -0
- package/handlers/database-migration-handler.js +227 -0
- package/handlers/integration-event-dispatcher.js +54 -0
- package/handlers/routers/HEALTHCHECK.md +342 -0
- package/handlers/routers/auth.js +15 -0
- package/handlers/routers/db-migration.handler.js +29 -0
- package/handlers/routers/db-migration.js +256 -0
- package/handlers/routers/health.js +519 -0
- package/handlers/routers/integration-defined-routers.js +45 -0
- package/handlers/routers/integration-webhook-routers.js +67 -0
- package/handlers/routers/user.js +63 -0
- package/handlers/routers/websocket.js +57 -0
- package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
- package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
- package/handlers/workers/db-migration.js +352 -0
- package/handlers/workers/integration-defined-workers.js +27 -0
- package/index.js +77 -22
- package/integrations/WEBHOOK-QUICKSTART.md +151 -0
- package/integrations/index.js +12 -10
- package/integrations/integration-base.js +296 -54
- package/integrations/integration-router.js +381 -182
- package/integrations/options.js +1 -1
- package/integrations/repositories/integration-mapping-repository-factory.js +50 -0
- package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
- package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
- package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
- package/integrations/repositories/integration-mapping-repository.js +156 -0
- package/integrations/repositories/integration-repository-factory.js +44 -0
- package/integrations/repositories/integration-repository-interface.js +127 -0
- package/integrations/repositories/integration-repository-mongo.js +303 -0
- package/integrations/repositories/integration-repository-postgres.js +352 -0
- package/integrations/repositories/process-repository-factory.js +46 -0
- package/integrations/repositories/process-repository-interface.js +90 -0
- package/integrations/repositories/process-repository-mongo.js +190 -0
- package/integrations/repositories/process-repository-postgres.js +217 -0
- package/integrations/tests/doubles/dummy-integration-class.js +83 -0
- package/integrations/tests/doubles/test-integration-repository.js +99 -0
- package/integrations/use-cases/create-integration.js +83 -0
- package/integrations/use-cases/create-process.js +128 -0
- package/integrations/use-cases/delete-integration-for-user.js +101 -0
- package/integrations/use-cases/find-integration-context-by-external-entity-id.js +72 -0
- package/integrations/use-cases/get-integration-for-user.js +78 -0
- package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
- package/integrations/use-cases/get-integration-instance.js +83 -0
- package/integrations/use-cases/get-integrations-for-user.js +87 -0
- package/integrations/use-cases/get-possible-integrations.js +27 -0
- package/integrations/use-cases/get-process.js +87 -0
- package/integrations/use-cases/index.js +19 -0
- package/integrations/use-cases/load-integration-context.js +71 -0
- package/integrations/use-cases/update-integration-messages.js +44 -0
- package/integrations/use-cases/update-integration-status.js +32 -0
- package/integrations/use-cases/update-integration.js +93 -0
- package/integrations/use-cases/update-process-metrics.js +201 -0
- package/integrations/use-cases/update-process-state.js +119 -0
- package/integrations/utils/map-integration-dto.js +36 -0
- package/jest-global-setup-noop.js +3 -0
- package/jest-global-teardown-noop.js +3 -0
- package/logs/logger.js +0 -4
- package/{module-plugin → modules}/entity.js +1 -1
- package/{module-plugin → modules}/index.js +0 -8
- package/modules/module-factory.js +56 -0
- package/modules/module.js +221 -0
- package/modules/repositories/module-repository-factory.js +33 -0
- package/modules/repositories/module-repository-interface.js +129 -0
- package/modules/repositories/module-repository-mongo.js +377 -0
- package/modules/repositories/module-repository-postgres.js +426 -0
- package/modules/repositories/module-repository.js +316 -0
- package/{module-plugin → modules}/requester/requester.js +1 -0
- package/{module-plugin → modules}/test/mock-api/api.js +8 -3
- package/{module-plugin → modules}/test/mock-api/definition.js +12 -8
- package/modules/tests/doubles/test-module-factory.js +16 -0
- package/modules/tests/doubles/test-module-repository.js +39 -0
- package/modules/use-cases/get-entities-for-user.js +32 -0
- package/modules/use-cases/get-entity-options-by-id.js +59 -0
- package/modules/use-cases/get-entity-options-by-type.js +34 -0
- package/modules/use-cases/get-module-instance-from-type.js +31 -0
- package/modules/use-cases/get-module.js +55 -0
- package/modules/use-cases/process-authorization-callback.js +122 -0
- package/modules/use-cases/refresh-entity-options.js +59 -0
- package/modules/use-cases/test-module-auth.js +55 -0
- package/modules/utils/map-module-dto.js +18 -0
- package/package.json +82 -50
- package/prisma-mongodb/schema.prisma +362 -0
- package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
- package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
- package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
- package/prisma-postgresql/migrations/migration_lock.toml +3 -0
- package/prisma-postgresql/schema.prisma +345 -0
- package/queues/queuer-util.js +28 -15
- package/syncs/manager.js +468 -443
- package/syncs/repositories/sync-repository-factory.js +38 -0
- package/syncs/repositories/sync-repository-interface.js +109 -0
- package/syncs/repositories/sync-repository-mongo.js +239 -0
- package/syncs/repositories/sync-repository-postgres.js +319 -0
- package/syncs/sync.js +0 -1
- package/token/repositories/token-repository-factory.js +33 -0
- package/token/repositories/token-repository-interface.js +131 -0
- package/token/repositories/token-repository-mongo.js +212 -0
- package/token/repositories/token-repository-postgres.js +257 -0
- package/token/repositories/token-repository.js +219 -0
- package/types/core/index.d.ts +2 -2
- package/types/integrations/index.d.ts +2 -6
- package/types/module-plugin/index.d.ts +5 -59
- package/types/syncs/index.d.ts +0 -2
- package/user/repositories/user-repository-factory.js +46 -0
- package/user/repositories/user-repository-interface.js +198 -0
- package/user/repositories/user-repository-mongo.js +291 -0
- package/user/repositories/user-repository-postgres.js +350 -0
- package/user/tests/doubles/test-user-repository.js +72 -0
- package/user/use-cases/authenticate-user.js +127 -0
- package/user/use-cases/authenticate-with-shared-secret.js +48 -0
- package/user/use-cases/create-individual-user.js +61 -0
- package/user/use-cases/create-organization-user.js +47 -0
- package/user/use-cases/create-token-for-user-id.js +30 -0
- package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
- package/user/use-cases/get-user-from-bearer-token.js +77 -0
- package/user/use-cases/get-user-from-x-frigg-headers.js +106 -0
- package/user/use-cases/login-user.js +122 -0
- package/user/user.js +93 -0
- package/utils/backend-path.js +38 -0
- package/utils/index.js +6 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +37 -0
- package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
- package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
- package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
- package/websocket/repositories/websocket-connection-repository.js +161 -0
- package/database/models/State.js +0 -9
- package/database/models/Token.js +0 -70
- package/database/mongo.js +0 -45
- package/encrypt/Cryptor.test.js +0 -32
- package/encrypt/encrypt.js +0 -132
- package/encrypt/encrypt.test.js +0 -1069
- package/errors/base-error.test.js +0 -32
- package/errors/fetch-error.test.js +0 -79
- package/errors/halt-error.test.js +0 -11
- package/errors/validation-errors.test.js +0 -120
- package/integrations/create-frigg-backend.js +0 -31
- package/integrations/integration-factory.js +0 -251
- package/integrations/integration-mapping.js +0 -43
- package/integrations/integration-model.js +0 -46
- package/integrations/integration-user.js +0 -144
- package/integrations/test/integration-base.test.js +0 -144
- package/lambda/TimeoutCatcher.test.js +0 -68
- package/logs/logger.test.js +0 -76
- package/module-plugin/auther.js +0 -393
- package/module-plugin/credential.js +0 -22
- package/module-plugin/entity-manager.js +0 -70
- package/module-plugin/manager.js +0 -169
- package/module-plugin/module-factory.js +0 -61
- package/module-plugin/requester/requester.test.js +0 -28
- package/module-plugin/test/auther.test.js +0 -97
- /package/{module-plugin → modules}/ModuleConstants.js +0 -0
- /package/{module-plugin → modules}/requester/api-key.js +0 -0
- /package/{module-plugin → modules}/requester/basic.js +0 -0
- /package/{module-plugin → modules}/requester/oauth-2.js +0 -0
- /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
const { prisma } = require('../../database/prisma');
|
|
2
|
+
const { ModuleRepositoryInterface } = require('./module-repository-interface');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* PostgreSQL Module Repository Adapter
|
|
6
|
+
* Handles Entity model operations for external service entities with PostgreSQL
|
|
7
|
+
*
|
|
8
|
+
* PostgreSQL-specific characteristics:
|
|
9
|
+
* - Uses Int IDs with autoincrement
|
|
10
|
+
* - Requires ID conversion: String (app layer) ↔ Int (database)
|
|
11
|
+
* - All returned IDs are converted to strings for application layer consistency
|
|
12
|
+
*/
|
|
13
|
+
class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
this.prisma = prisma;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Convert string ID to integer for PostgreSQL queries
|
|
21
|
+
* @private
|
|
22
|
+
* @param {string|number|null|undefined} id - ID to convert
|
|
23
|
+
* @returns {number|null|undefined} Integer ID or null/undefined
|
|
24
|
+
* @throws {Error} If ID cannot be converted to integer
|
|
25
|
+
*/
|
|
26
|
+
_convertId(id) {
|
|
27
|
+
if (id === null || id === undefined) return id;
|
|
28
|
+
const parsed = parseInt(id, 10);
|
|
29
|
+
if (isNaN(parsed)) {
|
|
30
|
+
throw new Error(`Invalid ID: ${id} cannot be converted to integer`);
|
|
31
|
+
}
|
|
32
|
+
return parsed;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Convert any value to string (handles null/undefined)
|
|
37
|
+
* @private
|
|
38
|
+
* @param {*} value - Value to convert
|
|
39
|
+
* @returns {string|null|undefined} String value or null/undefined
|
|
40
|
+
*/
|
|
41
|
+
_toString(value) {
|
|
42
|
+
if (value === null || value === undefined) return value;
|
|
43
|
+
return String(value);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Convert credential object IDs to strings
|
|
48
|
+
* @private
|
|
49
|
+
* @param {Object|null} credential - Credential object from database
|
|
50
|
+
* @returns {Object|null} Credential with string IDs
|
|
51
|
+
*/
|
|
52
|
+
_convertCredentialIds(credential) {
|
|
53
|
+
if (!credential) return credential;
|
|
54
|
+
return {
|
|
55
|
+
...credential,
|
|
56
|
+
id: credential.id?.toString(),
|
|
57
|
+
userId: credential.userId?.toString(),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Fetch credential by ID separately to ensure encryption extension processes it
|
|
63
|
+
* This fixes the bug where credentials fetched via include bypass decryption
|
|
64
|
+
* @private
|
|
65
|
+
* @param {number|null|undefined} credentialId - Credential ID (integer for PostgreSQL)
|
|
66
|
+
* @returns {Promise<Object|null>} Decrypted credential with string IDs or null
|
|
67
|
+
*/
|
|
68
|
+
async _fetchCredential(credentialId) {
|
|
69
|
+
if (!credentialId) return null;
|
|
70
|
+
|
|
71
|
+
const credential = await this.prisma.credential.findUnique({
|
|
72
|
+
where: { id: credentialId },
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return this._convertCredentialIds(credential);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Fetch multiple credentials in bulk separately to ensure decryption
|
|
80
|
+
* More efficient than fetching one-by-one for arrays of entities
|
|
81
|
+
* @private
|
|
82
|
+
* @param {Array<number>} credentialIds - Array of credential IDs (integers for PostgreSQL)
|
|
83
|
+
* @returns {Promise<Map<number, Object>>} Map of credentialId -> credential object
|
|
84
|
+
*/
|
|
85
|
+
async _fetchCredentialsBulk(credentialIds) {
|
|
86
|
+
if (!credentialIds || credentialIds.length === 0) {
|
|
87
|
+
return new Map();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const validIds = credentialIds.filter(id => id !== null && id !== undefined);
|
|
91
|
+
|
|
92
|
+
if (validIds.length === 0) {
|
|
93
|
+
return new Map();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const credentials = await this.prisma.credential.findMany({
|
|
97
|
+
where: { id: { in: validIds } },
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const credentialMap = new Map();
|
|
101
|
+
for (const credential of credentials) {
|
|
102
|
+
credentialMap.set(
|
|
103
|
+
credential.id,
|
|
104
|
+
this._convertCredentialIds(credential)
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return credentialMap;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Find entity by ID with credential
|
|
113
|
+
* Replaces: Entity.findById(entityId).populate('credential')
|
|
114
|
+
*
|
|
115
|
+
* @param {string} entityId - Entity ID (string from application layer)
|
|
116
|
+
* @returns {Promise<Object>} Entity object with string IDs
|
|
117
|
+
* @throws {Error} If entity not found
|
|
118
|
+
*/
|
|
119
|
+
async findEntityById(entityId) {
|
|
120
|
+
const intId = this._convertId(entityId);
|
|
121
|
+
|
|
122
|
+
const entity = await this.prisma.entity.findUnique({
|
|
123
|
+
where: { id: intId },
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
if (!entity) {
|
|
127
|
+
throw new Error(`Entity ${entityId} not found`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const credential = await this._fetchCredential(entity.credentialId);
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
id: entity.id.toString(),
|
|
134
|
+
accountId: entity.accountId,
|
|
135
|
+
credential,
|
|
136
|
+
userId: entity.userId?.toString(),
|
|
137
|
+
name: entity.name,
|
|
138
|
+
externalId: entity.externalId,
|
|
139
|
+
moduleName: entity.moduleName,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Find all entities for a user
|
|
145
|
+
* Replaces: Entity.find({ user: userId }).populate('credential')
|
|
146
|
+
*
|
|
147
|
+
* @param {string} userId - User ID (string from application layer)
|
|
148
|
+
* @returns {Promise<Array>} Array of entity objects with string IDs
|
|
149
|
+
*/
|
|
150
|
+
async findEntitiesByUserId(userId) {
|
|
151
|
+
const intUserId = this._convertId(userId);
|
|
152
|
+
|
|
153
|
+
const entities = await this.prisma.entity.findMany({
|
|
154
|
+
where: { userId: intUserId },
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
158
|
+
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
159
|
+
|
|
160
|
+
return entities.map((e) => ({
|
|
161
|
+
id: e.id.toString(),
|
|
162
|
+
accountId: e.accountId,
|
|
163
|
+
credential: credentialMap.get(e.credentialId) || null,
|
|
164
|
+
userId: e.userId?.toString(),
|
|
165
|
+
name: e.name,
|
|
166
|
+
externalId: e.externalId,
|
|
167
|
+
moduleName: e.moduleName,
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Find entities by array of IDs
|
|
173
|
+
* Replaces: Entity.find({ _id: { $in: entitiesIds } }).populate('credential')
|
|
174
|
+
*
|
|
175
|
+
* @param {Array<string>} entitiesIds - Array of entity IDs (strings from application layer)
|
|
176
|
+
* @returns {Promise<Array>} Array of entity objects with string IDs
|
|
177
|
+
*/
|
|
178
|
+
async findEntitiesByIds(entitiesIds) {
|
|
179
|
+
const intIds = entitiesIds.map((id) => this._convertId(id));
|
|
180
|
+
|
|
181
|
+
const entities = await this.prisma.entity.findMany({
|
|
182
|
+
where: { id: { in: intIds } },
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
186
|
+
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
187
|
+
|
|
188
|
+
return entities.map((e) => ({
|
|
189
|
+
id: e.id.toString(),
|
|
190
|
+
accountId: e.accountId,
|
|
191
|
+
credential: credentialMap.get(e.credentialId) || null,
|
|
192
|
+
userId: e.userId?.toString(),
|
|
193
|
+
name: e.name,
|
|
194
|
+
externalId: e.externalId,
|
|
195
|
+
moduleName: e.moduleName,
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Find entities by user ID and module name
|
|
201
|
+
* Replaces: Entity.find({ user: userId, moduleName: moduleName }).populate('credential')
|
|
202
|
+
*
|
|
203
|
+
* @param {string} userId - User ID (string from application layer)
|
|
204
|
+
* @param {string} moduleName - Module name
|
|
205
|
+
* @returns {Promise<Array>} Array of entity objects with string IDs
|
|
206
|
+
*/
|
|
207
|
+
async findEntitiesByUserIdAndModuleName(userId, moduleName) {
|
|
208
|
+
const intUserId = this._convertId(userId);
|
|
209
|
+
|
|
210
|
+
const entities = await this.prisma.entity.findMany({
|
|
211
|
+
where: {
|
|
212
|
+
userId: intUserId,
|
|
213
|
+
moduleName,
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
218
|
+
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
219
|
+
|
|
220
|
+
return entities.map((e) => ({
|
|
221
|
+
id: e.id.toString(),
|
|
222
|
+
accountId: e.accountId,
|
|
223
|
+
credential: credentialMap.get(e.credentialId) || null,
|
|
224
|
+
userId: e.userId?.toString(),
|
|
225
|
+
name: e.name,
|
|
226
|
+
externalId: e.externalId,
|
|
227
|
+
moduleName: e.moduleName,
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Remove credential reference from entity
|
|
233
|
+
* Replaces: Entity.updateOne({ _id: entityId }, { $unset: { credential: "" } })
|
|
234
|
+
*
|
|
235
|
+
* @param {string} entityId - Entity ID (string from application layer)
|
|
236
|
+
* @returns {Promise<boolean>} Success indicator
|
|
237
|
+
*/
|
|
238
|
+
async unsetCredential(entityId) {
|
|
239
|
+
const intId = this._convertId(entityId);
|
|
240
|
+
await this.prisma.entity.update({
|
|
241
|
+
where: { id: intId },
|
|
242
|
+
data: { credentialId: null },
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Find entity by filter criteria
|
|
250
|
+
*
|
|
251
|
+
* @param {Object} filter - Filter criteria
|
|
252
|
+
* @returns {Promise<Object|null>} Entity object with string IDs or null
|
|
253
|
+
*/
|
|
254
|
+
async findEntity(filter) {
|
|
255
|
+
const where = this._convertFilterToWhere(filter);
|
|
256
|
+
|
|
257
|
+
const entity = await this.prisma.entity.findFirst({
|
|
258
|
+
where,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
if (!entity) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const credential = await this._fetchCredential(entity.credentialId);
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
id: entity.id.toString(),
|
|
269
|
+
accountId: entity.accountId,
|
|
270
|
+
credential,
|
|
271
|
+
userId: entity.userId?.toString(),
|
|
272
|
+
name: entity.name,
|
|
273
|
+
externalId: entity.externalId,
|
|
274
|
+
moduleName: entity.moduleName,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Create a new entity
|
|
280
|
+
* Replaces: Entity.create(entityData)
|
|
281
|
+
*
|
|
282
|
+
* @param {Object} entityData - Entity data (with string IDs from application layer)
|
|
283
|
+
* @returns {Promise<Object>} Created entity object with string IDs
|
|
284
|
+
*/
|
|
285
|
+
async createEntity(entityData) {
|
|
286
|
+
const data = {
|
|
287
|
+
userId: this._convertId(entityData.user || entityData.userId),
|
|
288
|
+
credentialId: this._convertId(
|
|
289
|
+
entityData.credential || entityData.credentialId
|
|
290
|
+
),
|
|
291
|
+
name: entityData.name,
|
|
292
|
+
moduleName: entityData.moduleName,
|
|
293
|
+
externalId: entityData.externalId,
|
|
294
|
+
accountId: entityData.accountId,
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const entity = await this.prisma.entity.create({
|
|
298
|
+
data,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const credential = await this._fetchCredential(entity.credentialId);
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
id: entity.id.toString(),
|
|
305
|
+
accountId: entity.accountId,
|
|
306
|
+
credential,
|
|
307
|
+
userId: entity.userId?.toString(),
|
|
308
|
+
name: entity.name,
|
|
309
|
+
externalId: entity.externalId,
|
|
310
|
+
moduleName: entity.moduleName,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Update an entity by ID
|
|
316
|
+
* Replaces: Entity.findByIdAndUpdate(entityId, updates, { new: true })
|
|
317
|
+
*
|
|
318
|
+
* @param {string} entityId - Entity ID to update (string from application layer)
|
|
319
|
+
* @param {Object} updates - Fields to update (with string IDs from application layer)
|
|
320
|
+
* @returns {Promise<Object|null>} Updated entity object with string IDs or null if not found
|
|
321
|
+
*/
|
|
322
|
+
async updateEntity(entityId, updates) {
|
|
323
|
+
const data = {};
|
|
324
|
+
if (updates.user !== undefined)
|
|
325
|
+
data.userId = this._convertId(updates.user);
|
|
326
|
+
if (updates.userId !== undefined)
|
|
327
|
+
data.userId = this._convertId(updates.userId);
|
|
328
|
+
if (updates.credential !== undefined)
|
|
329
|
+
data.credentialId = this._convertId(updates.credential);
|
|
330
|
+
if (updates.credentialId !== undefined)
|
|
331
|
+
data.credentialId = this._convertId(updates.credentialId);
|
|
332
|
+
if (updates.name !== undefined) data.name = updates.name;
|
|
333
|
+
if (updates.moduleName !== undefined)
|
|
334
|
+
data.moduleName = updates.moduleName;
|
|
335
|
+
if (updates.externalId !== undefined)
|
|
336
|
+
data.externalId = updates.externalId;
|
|
337
|
+
if (updates.accountId !== undefined) data.accountId = updates.accountId;
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
const intId = this._convertId(entityId);
|
|
341
|
+
|
|
342
|
+
const entity = await this.prisma.entity.update({
|
|
343
|
+
where: { id: intId },
|
|
344
|
+
data,
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
const credential = await this._fetchCredential(entity.credentialId);
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
id: entity.id.toString(),
|
|
351
|
+
accountId: entity.accountId,
|
|
352
|
+
credential,
|
|
353
|
+
userId: entity.userId?.toString(),
|
|
354
|
+
name: entity.name,
|
|
355
|
+
externalId: entity.externalId,
|
|
356
|
+
moduleName: entity.moduleName,
|
|
357
|
+
};
|
|
358
|
+
} catch (error) {
|
|
359
|
+
if (error.code === 'P2025') {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Delete an entity by ID
|
|
368
|
+
* Replaces: Entity.deleteOne({ _id: entityId })
|
|
369
|
+
*
|
|
370
|
+
* @param {string} entityId - Entity ID to delete (string from application layer)
|
|
371
|
+
* @returns {Promise<boolean>} True if deleted successfully
|
|
372
|
+
*/
|
|
373
|
+
async deleteEntity(entityId) {
|
|
374
|
+
try {
|
|
375
|
+
const intId = this._convertId(entityId);
|
|
376
|
+
await this.prisma.entity.delete({
|
|
377
|
+
where: { id: intId },
|
|
378
|
+
});
|
|
379
|
+
return true;
|
|
380
|
+
} catch (error) {
|
|
381
|
+
if (error.code === 'P2025') {
|
|
382
|
+
// Record not found
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Convert Mongoose-style filter to Prisma where clause (converting IDs to Int)
|
|
391
|
+
* @private
|
|
392
|
+
* @param {Object} filter - Mongoose filter (with string IDs from application layer)
|
|
393
|
+
* @returns {Object} Prisma where clause (with Int IDs for PostgreSQL)
|
|
394
|
+
*/
|
|
395
|
+
_convertFilterToWhere(filter) {
|
|
396
|
+
const where = {};
|
|
397
|
+
|
|
398
|
+
// Handle _id field (Mongoose uses _id, Prisma uses id)
|
|
399
|
+
if (filter._id) {
|
|
400
|
+
where.id = this._convertId(filter._id);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Handle user field (Mongoose uses user, Prisma uses userId)
|
|
404
|
+
if (filter.user) {
|
|
405
|
+
where.userId = this._convertId(filter.user);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Handle credential field (Mongoose uses credential, Prisma uses credentialId)
|
|
409
|
+
if (filter.credential) {
|
|
410
|
+
where.credentialId = this._convertId(filter.credential);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Copy other fields directly (converting IDs)
|
|
414
|
+
if (filter.id) where.id = this._convertId(filter.id);
|
|
415
|
+
if (filter.userId) where.userId = this._convertId(filter.userId);
|
|
416
|
+
if (filter.credentialId)
|
|
417
|
+
where.credentialId = this._convertId(filter.credentialId);
|
|
418
|
+
if (filter.name) where.name = filter.name;
|
|
419
|
+
if (filter.moduleName) where.moduleName = filter.moduleName;
|
|
420
|
+
if (filter.externalId) where.externalId = this._toString(filter.externalId);
|
|
421
|
+
|
|
422
|
+
return where;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
module.exports = { ModuleRepositoryPostgres };
|